/+junk/c_sdl_joypad_ducktape

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/%2Bjunk/c_sdl_joypad_ducktape

« back to all changes in this revision

Viewing changes to src/duktape.c

  • Committer: Gustav Hartvigsson
  • Date: 2014-06-15 17:02:39 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20140615170239-4xkvyjbrxfl760zz
* Started work on porting to Ducktape from MozJs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Single file autogenerated distributable for Duktape 0.10.0.
 
3
 *  Git commit 78c73a152c35749ff5fe237209c353503ea6534d (v0.9.0-664-g78c73a1).
 
4
 *
 
5
 *  See Duktape AUTHORS.txt and LICENSE.txt for copyright and
 
6
 *  licensing information.
 
7
 */
 
8
 
 
9
#line 1 "duk_internal.h"
 
10
/*
 
11
 *  Top-level include file to be used for all (internal) source files.
 
12
 *
 
13
 *  Source files should not include individual header files, as they
 
14
 *  have not been designed to be individually included.
 
15
 */
 
16
 
 
17
#ifndef DUK_INTERNAL_H_INCLUDED
 
18
#define DUK_INTERNAL_H_INCLUDED
 
19
 
 
20
/*
 
21
 *  Platform specific handling: detection of features, system headers are
 
22
 *  included etc.  Duktape.h contains its own feature detection for those
 
23
 *  features the external API absolutely needs.  Duktape.h detection results
 
24
 *  must match duk_features.h, so duk_features_sanity.h is included to check
 
25
 *  for consistency.
 
26
 */
 
27
 
 
28
#line 1 "duk_features.h"
 
29
/*
 
30
 *  Determine platform features, select feature selection defines
 
31
 *  (e.g. _XOPEN_SOURCE), include system headers, and define DUK_USE_XXX
 
32
 *  defines which are (only) checked in Duktape internal code for
 
33
 *  activated features.  Duktape feature selection is based on automatic
 
34
 *  feature detection, user supplied DUK_OPT_xxx defines, and optionally
 
35
 *  a "duk_custom.h" user header (if DUK_OPT_HAVE_CUSTOM_H is defined).
 
36
 *
 
37
 *  This file is included by duk_internal.h before anything else is
 
38
 *  included.  Feature selection defines (e.g. _XOPEN_SOURCE) are defined
 
39
 *  here before any system headers are included (which is a requirement for
 
40
 *  system headers to work correctly).  This file is responsible for including
 
41
 *  all system headers and contains all platform dependent cruft in general.
 
42
 *
 
43
 *  The public duktape.h has minimal feature detection required by the public
 
44
 *  API (for instance use of variadic macros is detected there).  Duktape.h
 
45
 *  exposes its detection results as DUK_API_xxx.  The public header and the
 
46
 *  implementation must agree on e.g. names and argument lists of exposed
 
47
 *  calls; these are checked by duk_features_sanity.h (duktape.h is not yet
 
48
 *  included when this file is included to avoid fouling up feature selection
 
49
 *  defines).
 
50
 *
 
51
 *  The general order of handling:
 
52
 *    - Compiler feature detection (require no includes)
 
53
 *    - Intermediate platform detection (-> easier platform defines)
 
54
 *    - Platform detection, system includes, byte order detection, etc
 
55
 *    - ANSI C wrappers (e.g. DUK_MEMCMP), wrappers for constants, etc
 
56
 *    - DUK_USE_xxx defines are resolved based on input defines
 
57
 *    - Duktape Date provider settings
 
58
 *    - Final sanity checks
 
59
 *
 
60
 *  DUK_F_XXX are internal feature detection macros which should not
 
61
 *  be used outside this header.
 
62
 *
 
63
 *  Useful resources:
 
64
 *
 
65
 *    http://sourceforge.net/p/predef/wiki/Home/
 
66
 *    http://sourceforge.net/p/predef/wiki/Architectures/
 
67
 *    http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
 
68
 *    http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types
 
69
 *
 
70
 *  Preprocessor defines available in a particular GCC:
 
71
 *
 
72
 *    gcc -dM -E - </dev/null   # http://www.brain-dump.org/blog/entry/107
 
73
 */
 
74
 
 
75
#ifndef DUK_FEATURES_H_INCLUDED
 
76
#define DUK_FEATURES_H_INCLUDED
 
77
 
 
78
/*
 
79
 *  Compiler features
 
80
 */
 
81
 
 
82
#undef DUK_F_C99
 
83
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 
84
#define DUK_F_C99
 
85
#endif
 
86
 
 
87
#undef DUK_F_CPP
 
88
#if defined(__cplusplus)
 
89
#define DUK_F_CPP
 
90
#endif
 
91
 
 
92
#undef DUK_F_CPP11
 
93
#if defined(__cplusplus) && (__cplusplus >= 201103L)
 
94
#define DUK_F_CPP11
 
95
#endif
 
96
 
 
97
/*
 
98
 *  Provides the duk_rdtsc() inline function (if available)
 
99
 *
 
100
 *  See: http://www.mcs.anl.gov/~kazutomo/rdtsc.html
 
101
 */
 
102
 
 
103
/* XXX: more accurate detection of what gcc versions work; more inline
 
104
 * asm versions for other compilers.
 
105
 */
 
106
#if defined(__GNUC__) && defined(__i386__) && \
 
107
    !defined(__cplusplus) /* unsigned long long not standard */
 
108
static __inline__ unsigned long long duk_rdtsc(void) {
 
109
        unsigned long long int x;
 
110
        __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
 
111
        return x;
 
112
}
 
113
#define DUK_RDTSC_AVAILABLE 1
 
114
#elif defined(__GNUC__) && defined(__x86_64__) && \
 
115
    !defined(__cplusplus) /* unsigned long long not standard */
 
116
static __inline__ unsigned long long duk_rdtsc(void) {
 
117
        unsigned hi, lo;
 
118
        __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
 
119
        return ((unsigned long long) lo) | (((unsigned long long) hi) << 32);
 
120
}
 
121
#define DUK_RDTSC_AVAILABLE 1
 
122
#else
 
123
/* not available */
 
124
#undef DUK_RDTSC_AVAILABLE
 
125
#endif
 
126
 
 
127
/*
 
128
 *  Intermediate platform, architecture, and compiler detection.  These are
 
129
 *  hopelessly intertwined - e.g. architecture defines depend on compiler etc.
 
130
 *
 
131
 *  Provide easier defines for platforms and compilers which are often tricky
 
132
 *  or verbose to detect.  The intent is not to provide intermediate defines for
 
133
 *  all features; only if existing feature defines are inconvenient.
 
134
 */
 
135
 
 
136
/* Intel x86 (32-bit) */
 
137
#if defined(i386) || defined(__i386) || defined(__i386__) || \
 
138
    defined(__i486__) || defined(__i586__) || defined(__i686__) || \
 
139
    defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \
 
140
    defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__)
 
141
#define DUK_F_X86
 
142
#endif
 
143
 
 
144
/* AMD64 (64-bit) */
 
145
#if defined(__amd64__) || defined(__amd64) || \
 
146
    defined(__x86_64__) || defined(__x86_64) || \
 
147
    defined(_M_X64) || defined(_M_AMD64)
 
148
#define DUK_F_X64
 
149
#endif
 
150
 
 
151
/* FIXME: X32: pointers are 32-bit so packed format can be used, but X32
 
152
 * support is not yet mature.
 
153
 */
 
154
 
 
155
/* ARM */
 
156
#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM)
 
157
#define DUK_F_ARM
 
158
#endif
 
159
 
 
160
/* MIPS */
 
161
#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \
 
162
    defined(_R3000) || defined(_R4000) || defined(_R5900) || \
 
163
    defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \
 
164
    defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \
 
165
    defined(__mips) || defined(__MIPS__)
 
166
#define DUK_F_MIPS
 
167
#endif
 
168
 
 
169
/* Motorola 68K.  Not defined by VBCC, so user must define one of these
 
170
 * manually when using VBCC.
 
171
 */
 
172
#if defined(__m68k__) || defined(M68000) || defined(__MC68K__)
 
173
#define DUK_F_M68K
 
174
#endif
 
175
 
 
176
/* Linux */
 
177
#if defined(__linux) || defined(__linux__) || defined(linux)
 
178
#define DUK_F_LINUX
 
179
#endif
 
180
 
 
181
/* FreeBSD */
 
182
#if defined(__FreeBSD__) || defined(__FreeBSD)
 
183
#define DUK_F_FREEBSD
 
184
#endif
 
185
 
 
186
/* NetBSD */
 
187
#if defined(__NetBSD__) || defined(__NetBSD)
 
188
#define DUK_F_NETBSD
 
189
#endif
 
190
 
 
191
/* OpenBSD */
 
192
#if defined(__OpenBSD__) || defined(__OpenBSD)
 
193
#define DUK_F_OPENBSD
 
194
#endif
 
195
 
 
196
/* BSD variant */
 
197
#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \
 
198
    defined(__bsdi__) || defined(__DragonFly__)
 
199
#define DUK_F_BSD
 
200
#endif
 
201
 
 
202
/* Generic Unix */
 
203
#if defined(__unix) || defined(__unix__) || defined(unix) || \
 
204
    defined(DUK_F_LINUX) || defined(DUK_F_BSD)
 
205
#define DUK_F_UNIX
 
206
#endif
 
207
 
 
208
/* Windows (32-bit or above) */
 
209
#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \
 
210
    defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
 
211
#define DUK_F_WINDOWS
 
212
#endif
 
213
 
 
214
/* Atari ST TOS. __TOS__ defined by PureC (which doesn't work as a target now
 
215
 * because int is 16-bit, to be fixed).  No platform define in VBCC apparently,
 
216
 * so to use with VBCC, user must define '__TOS__' manually.
 
217
  */
 
218
#if defined(__TOS__)
 
219
#define DUK_F_TOS
 
220
#endif
 
221
 
 
222
/* AmigaOS.  Neither AMIGA nor __amigaos__ is defined on VBCC, so user must
 
223
 * define 'AMIGA' manually.
 
224
 */
 
225
#if defined(AMIGA) || defined(__amigaos__)
 
226
#define DUK_F_AMIGAOS
 
227
#endif
 
228
 
 
229
/* Flash player (e.g. Crossbridge) */
 
230
#if defined(__FLASHPLAYER__)
 
231
#define DUK_F_FLASHPLAYER
 
232
#endif
 
233
 
 
234
/* Emscripten (provided explicitly by user), improve if possible */
 
235
#if defined(EMSCRIPTEN)
 
236
#define DUK_F_EMSCRIPTEN
 
237
#endif
 
238
 
 
239
/* QNX */
 
240
#if defined(__QNX__)
 
241
#define DUK_F_QNX
 
242
#endif
 
243
 
 
244
/* GCC and GCC version convenience define. */
 
245
#if defined(__GNUC__)
 
246
#define DUK_F_GCC
 
247
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
 
248
/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */
 
249
#define DUK_F_GCC_VERSION  (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
 
250
#else
 
251
#error cannot figure out gcc version
 
252
#endif
 
253
#endif
 
254
 
 
255
/* Clang */
 
256
#if defined(__clang__)
 
257
#define DUK_F_CLANG
 
258
#endif
 
259
 
 
260
/* MSVC */
 
261
#if defined(_MSC_VER)
 
262
#define DUK_F_MSVC
 
263
#endif
 
264
 
 
265
/* MinGW */
 
266
#if defined(__MINGW32__) || defined(__MINGW64__)
 
267
#define DUK_F_MINGW
 
268
#endif
 
269
 
 
270
/*
 
271
 *  Platform detection, system includes, Date provider selection.
 
272
 *
 
273
 *  Feature selection (e.g. _XOPEN_SOURCE) must happen before any system
 
274
 *  headers are included.
 
275
 *
 
276
 *  Date provider selection seems a bit out-of-place here, but since
 
277
 *  the date headers and provider functions are heavily platform
 
278
 *  specific, there's little point in duplicating the platform if-else
 
279
 *  ladder.  All platform specific Date provider functions are in
 
280
 *  duk_bi_date.c; here we provide appropriate #defines to enable them,
 
281
 *  and include all the necessary system headers so that duk_bi_date.c
 
282
 *  compiles.  Date "providers" are:
 
283
 *
 
284
 *    NOW = getting current time (required)
 
285
 *    TZO = getting local time offset (required)
 
286
 *    PRS = parse datetime (optional)
 
287
 *    FMT = format datetime (optional)
 
288
 *
 
289
 *  There's a lot of duplication here, unfortunately, because many
 
290
 *  platforms have similar (but not identical) headers, Date providers,
 
291
 *  etc.  The duplication could be removed by more complicated nested
 
292
 *  #ifdefs, but it would then be more difficult to make fixes which
 
293
 *  affect only a specific platform.
 
294
 *
 
295
 *  FIXME: add a way to provide custom functions to provide the critical
 
296
 *  primitives; this would be convenient when porting to unknown platforms
 
297
 *  (rather than muck with Duktape internals).
 
298
 */
 
299
 
 
300
#if defined(DUK_F_LINUX)
 
301
#ifndef _POSIX_C_SOURCE
 
302
#define _POSIX_C_SOURCE  200809L
 
303
#endif
 
304
#ifndef _GNU_SOURCE
 
305
#define _GNU_SOURCE      /* e.g. getdate_r */
 
306
#endif
 
307
#ifndef _XOPEN_SOURCE
 
308
#define _XOPEN_SOURCE    /* e.g. strptime */
 
309
#endif
 
310
#endif
 
311
 
 
312
#if defined(DUK_F_QNX)
 
313
/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */
 
314
#define _XOPEN_SOURCE    600
 
315
#define _POSIX_C_SOURCE  200112
 
316
#endif
 
317
 
 
318
#if defined(__APPLE__)
 
319
/* Mac OSX, iPhone, Darwin */
 
320
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
321
#define DUK_USE_DATE_TZO_GMTIME_R
 
322
#define DUK_USE_DATE_PRS_STRPTIME
 
323
#define DUK_USE_DATE_FMT_STRFTIME
 
324
#include <architecture/byte_order.h>
 
325
#include <limits.h>
 
326
#include <sys/param.h>
 
327
#include <sys/time.h>
 
328
#include <time.h>
 
329
#elif defined(DUK_F_OPENBSD)
 
330
/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */
 
331
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
332
#define DUK_USE_DATE_TZO_GMTIME_R
 
333
#define DUK_USE_DATE_PRS_STRPTIME
 
334
#define DUK_USE_DATE_FMT_STRFTIME
 
335
#include <sys/types.h>
 
336
#include <sys/endian.h>
 
337
#include <limits.h>
 
338
#include <sys/param.h>
 
339
#include <sys/time.h>
 
340
#include <time.h>
 
341
#elif defined(DUK_F_BSD)
 
342
/* other BSD */
 
343
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
344
#define DUK_USE_DATE_TZO_GMTIME_R
 
345
#define DUK_USE_DATE_PRS_STRPTIME
 
346
#define DUK_USE_DATE_FMT_STRFTIME
 
347
#include <sys/types.h>
 
348
#include <sys/endian.h>
 
349
#include <limits.h>
 
350
#include <sys/param.h>
 
351
#include <sys/time.h>
 
352
#include <time.h>
 
353
#elif defined(DUK_F_TOS)
 
354
/* Atari ST TOS */
 
355
#define DUK_USE_DATE_NOW_TIME
 
356
#define DUK_USE_DATE_TZO_GMTIME
 
357
/* no parsing (not an error) */
 
358
#define DUK_USE_DATE_FMT_STRFTIME
 
359
#include <limits.h>
 
360
#include <time.h>
 
361
#elif defined(DUK_F_AMIGAOS)
 
362
#if defined(DUK_F_M68K)
 
363
/* AmigaOS on M68k */
 
364
#define DUK_USE_DATE_NOW_TIME
 
365
#define DUK_USE_DATE_TZO_GMTIME
 
366
/* no parsing (not an error) */
 
367
#define DUK_USE_DATE_FMT_STRFTIME
 
368
#include <limits.h>
 
369
#include <time.h>
 
370
#else
 
371
#error AmigaOS but not M68K, not supported now
 
372
#endif
 
373
#elif defined(DUK_F_WINDOWS)
 
374
/* Windows 32-bit and 64-bit are currently the same. */
 
375
/* MSVC does not have sys/param.h */
 
376
#define DUK_USE_DATE_NOW_WINDOWS
 
377
#define DUK_USE_DATE_TZO_WINDOWS
 
378
/* Note: PRS and FMT are intentionally left undefined for now.  This means
 
379
 * there is no platform specific date parsing/formatting but there is still
 
380
 * the ISO 8601 standard format.
 
381
 */
 
382
#include <windows.h>
 
383
#include <limits.h>
 
384
#elif defined(DUK_F_FLASHPLAYER)
 
385
/* Crossbridge */
 
386
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
387
#define DUK_USE_DATE_TZO_GMTIME_R
 
388
#define DUK_USE_DATE_PRS_STRPTIME
 
389
#define DUK_USE_DATE_FMT_STRFTIME
 
390
#include <endian.h>
 
391
#include <limits.h>
 
392
#include <sys/param.h>
 
393
#include <sys/time.h>
 
394
#include <time.h>
 
395
#elif defined(DUK_F_QNX)
 
396
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
397
#define DUK_USE_DATE_TZO_GMTIME_R
 
398
#define DUK_USE_DATE_PRS_STRPTIME
 
399
#define DUK_USE_DATE_FMT_STRFTIME
 
400
#include <sys/types.h>
 
401
#include <limits.h>
 
402
#include <sys/param.h>
 
403
#include <sys/time.h>
 
404
#include <time.h>
 
405
#elif defined(DUK_F_LINUX)
 
406
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
407
#define DUK_USE_DATE_TZO_GMTIME_R
 
408
#define DUK_USE_DATE_PRS_STRPTIME
 
409
#define DUK_USE_DATE_FMT_STRFTIME
 
410
#include <sys/types.h>
 
411
#include <endian.h>
 
412
#include <limits.h>
 
413
#include <sys/param.h>
 
414
#include <sys/time.h>
 
415
#include <time.h>
 
416
#elif defined(__posix)
 
417
/* POSIX */
 
418
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
419
#define DUK_USE_DATE_TZO_GMTIME_R
 
420
#define DUK_USE_DATE_PRS_STRPTIME
 
421
#define DUK_USE_DATE_FMT_STRFTIME
 
422
#include <sys/types.h>
 
423
#include <endian.h>
 
424
#include <limits.h>
 
425
#include <sys/param.h>
 
426
#include <sys/time.h>
 
427
#include <time.h>
 
428
#else
 
429
/* Other UNIX, hopefully others */
 
430
#define DUK_USE_DATE_NOW_GETTIMEOFDAY
 
431
#define DUK_USE_DATE_TZO_GMTIME_R
 
432
#define DUK_USE_DATE_PRS_STRPTIME
 
433
#define DUK_USE_DATE_FMT_STRFTIME
 
434
#include <sys/types.h>
 
435
#include <endian.h>
 
436
#include <limits.h>
 
437
#include <sys/param.h>
 
438
#include <sys/time.h>
 
439
#include <time.h>
 
440
#endif
 
441
 
 
442
/* Shared includes */
 
443
#include <stdio.h>
 
444
#include <stdlib.h>
 
445
#include <string.h>
 
446
#include <stdarg.h>  /* varargs */
 
447
#include <setjmp.h>
 
448
#include <stddef.h>  /* e.g. ptrdiff_t */
 
449
#ifdef DUK_F_TOS
 
450
/*FIXME*/
 
451
#else
 
452
/* XXX: technically C99 (C++11) but found in many systems */
 
453
#include <stdint.h>
 
454
#endif
 
455
#include <math.h>
 
456
 
 
457
/*
 
458
 *  Wrapper typedefs and constants for integer types, also sanity check types.
 
459
 *
 
460
 *  C99 typedefs are quite good but not always available, and we want to avoid
 
461
 *  forcibly redefining the C99 typedefs.  So, there are Duktape wrappers for
 
462
 *  all C99 typedefs and Duktape code should only use these typedefs.  The
 
463
 *  Duktape public API is problematic from type detection perspective and must
 
464
 *  be taken into account here.
 
465
 *
 
466
 *  Type detection when C99 is not supported is quite simplistic now and will
 
467
 *  only work on 32-bit platforms (64-bit platforms are OK with C99 types).
 
468
 *
 
469
 *  Pointer sizes are a portability problem: pointers to different types may
 
470
 *  have a different size and function pointers are very difficult to manage
 
471
 *  portably.
 
472
 *
 
473
 *  http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types
 
474
 *
 
475
 *  Note: avoid typecasts and computations in macro integer constants as they
 
476
 *  can then no longer be used in macro relational expressions (such as
 
477
 *  #if DUK_SIZE_MAX < 0xffffffffUL).  There is internal code which relies on
 
478
 *  being able to compare DUK_SIZE_MAX against a limit.
 
479
 */
 
480
 
 
481
/* FIXME: How to do reasonable automatic detection on older compilers,
 
482
 * and how to allow user override?
 
483
 */
 
484
 
 
485
/* FIXME: this assumption must be in place until no 'int' variables are
 
486
 * used anywhere, including the public Duktape API.  Also all printf()
 
487
 * format characters need to be changed.
 
488
 */
 
489
#if defined(INT_MAX)
 
490
#if INT_MAX < 2147483647
 
491
#error INT_MAX too small, expected int to be 32 bits at least
 
492
#endif
 
493
#else
 
494
#error INT_MAX not defined
 
495
#endif
 
496
 
 
497
/* Check that architecture is two's complement, standard C allows e.g.
 
498
 * INT_MIN to be -2**31+1 (instead of -2**31).
 
499
 */
 
500
#if defined(INT_MAX) && defined(INT_MIN)
 
501
#if INT_MAX != -(INT_MIN + 1)
 
502
#error platform does not seem complement of two
 
503
#endif
 
504
#else
 
505
#error cannot check complement of two
 
506
#endif
 
507
 
 
508
/* Intermediate define for 'have inttypes.h' */
 
509
#undef DUK_F_HAVE_INTTYPES
 
510
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
 
511
    !(defined(DUK_F_AMIGAOS) && defined(__VBCC__))
 
512
/* vbcc + AmigaOS has C99 but no inttypes.h */
 
513
#define DUK_F_HAVE_INTTYPES
 
514
#elif defined(__cplusplus) && (__cplusplus >= 201103L)
 
515
/* C++11 apparently ratified stdint.h */
 
516
#define DUK_F_HAVE_INTTYPES
 
517
#endif
 
518
 
 
519
/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise
 
520
 * through automatic detection.
 
521
 */
 
522
#if defined(DUK_F_HAVE_INTTYPES)
 
523
/* C99 */
 
524
#define DUK_F_HAVE_64BIT
 
525
#include <inttypes.h>
 
526
 
 
527
typedef uint8_t duk_uint8_t;
 
528
typedef int8_t duk_int8_t;
 
529
typedef uint16_t duk_uint16_t;
 
530
typedef int16_t duk_int16_t;
 
531
typedef uint32_t duk_uint32_t;
 
532
typedef int32_t duk_int32_t;
 
533
typedef uint64_t duk_uint64_t;
 
534
typedef int64_t duk_int64_t;
 
535
typedef uint_least8_t duk_uint_least8_t;
 
536
typedef int_least8_t duk_int_least8_t;
 
537
typedef uint_least16_t duk_uint_least16_t;
 
538
typedef int_least16_t duk_int_least16_t;
 
539
typedef uint_least32_t duk_uint_least32_t;
 
540
typedef int_least32_t duk_int_least32_t;
 
541
typedef uint_least64_t duk_uint_least64_t;
 
542
typedef int_least64_t duk_int_least64_t;
 
543
typedef uint_fast8_t duk_uint_fast8_t;
 
544
typedef int_fast8_t duk_int_fast8_t;
 
545
typedef uint_fast16_t duk_uint_fast16_t;
 
546
typedef int_fast16_t duk_int_fast16_t;
 
547
typedef uint_fast32_t duk_uint_fast32_t;
 
548
typedef int_fast32_t duk_int_fast32_t;
 
549
typedef uint_fast64_t duk_uint_fast64_t;
 
550
typedef int_fast64_t duk_int_fast64_t;
 
551
typedef uintptr_t duk_uintptr_t;
 
552
typedef intptr_t duk_intptr_t;
 
553
typedef uintmax_t duk_uintmax_t;
 
554
typedef intmax_t duk_intmax_t;
 
555
 
 
556
#define DUK_UINT8_MIN         0
 
557
#define DUK_UINT8_MAX         UINT8_MAX
 
558
#define DUK_INT8_MIN          INT8_MIN
 
559
#define DUK_INT8_MAX          INT8_MAX
 
560
#define DUK_UINT_LEAST8_MIN   0
 
561
#define DUK_UINT_LEAST8_MAX   UINT_LEAST8_MAX
 
562
#define DUK_INT_LEAST8_MIN    INT_LEAST8_MIN
 
563
#define DUK_INT_LEAST8_MAX    INT_LEAST8_MAX
 
564
#define DUK_UINT_FAST8_MIN    0
 
565
#define DUK_UINT_FAST8_MAX    UINT_FAST8_MAX
 
566
#define DUK_INT_FAST8_MIN     INT_FAST8_MIN
 
567
#define DUK_INT_FAST8_MAX     INT_FAST8_MAX
 
568
#define DUK_UINT16_MIN        0
 
569
#define DUK_UINT16_MAX        UINT16_MAX
 
570
#define DUK_INT16_MIN         INT16_MIN
 
571
#define DUK_INT16_MAX         INT16_MAX
 
572
#define DUK_UINT_LEAST16_MIN  0
 
573
#define DUK_UINT_LEAST16_MAX  UINT_LEAST16_MAX
 
574
#define DUK_INT_LEAST16_MIN   INT_LEAST16_MIN
 
575
#define DUK_INT_LEAST16_MAX   INT_LEAST16_MAX
 
576
#define DUK_UINT_FAST16_MIN   0
 
577
#define DUK_UINT_FAST16_MAX   UINT_FAST16_MAX
 
578
#define DUK_INT_FAST16_MIN    INT_FAST16_MIN
 
579
#define DUK_INT_FAST16_MAX    INT_FAST16_MAX
 
580
#define DUK_UINT32_MIN        0
 
581
#define DUK_UINT32_MAX        UINT32_MAX
 
582
#define DUK_INT32_MIN         INT32_MIN
 
583
#define DUK_INT32_MAX         INT32_MAX
 
584
#define DUK_UINT_LEAST32_MIN  0
 
585
#define DUK_UINT_LEAST32_MAX  UINT_LEAST32_MAX
 
586
#define DUK_INT_LEAST32_MIN   INT_LEAST32_MIN
 
587
#define DUK_INT_LEAST32_MAX   INT_LEAST32_MAX
 
588
#define DUK_UINT_FAST32_MIN   0
 
589
#define DUK_UINT_FAST32_MAX   UINT_FAST32_MAX
 
590
#define DUK_INT_FAST32_MIN    INT_FAST32_MIN
 
591
#define DUK_INT_FAST32_MAX    INT_FAST32_MAX
 
592
#define DUK_UINT64_MIN        0
 
593
#define DUK_UINT64_MAX        UINT64_MAX
 
594
#define DUK_INT64_MIN         INT64_MIN
 
595
#define DUK_INT64_MAX         INT64_MAX
 
596
#define DUK_UINT_LEAST64_MIN  0
 
597
#define DUK_UINT_LEAST64_MAX  UINT_LEAST64_MAX
 
598
#define DUK_INT_LEAST64_MIN   INT_LEAST64_MIN
 
599
#define DUK_INT_LEAST64_MAX   INT_LEAST64_MAX
 
600
#define DUK_UINT_FAST64_MIN   0
 
601
#define DUK_UINT_FAST64_MAX   UINT_FAST64_MAX
 
602
#define DUK_INT_FAST64_MIN    INT_FAST64_MIN
 
603
#define DUK_INT_FAST64_MAX    INT_FAST64_MAX
 
604
#define DUK_UINTPTR_MIN       0
 
605
#define DUK_UINTPTR_MAX       UINTPTR_MAX
 
606
#define DUK_INTPTR_MIN        INTPTR_MIN
 
607
#define DUK_INTPTR_MAX        INTPTR_MAX
 
608
#define DUK_UINTMAX_MIN       0
 
609
#define DUK_UINTMAX_MAX       UINTMAX_MAX
 
610
#define DUK_INTMAX_MIN        INTMAX_MIN
 
611
#define DUK_INTMAX_MAX        INTMAX_MAX
 
612
#define DUK_SIZE_MIN          0
 
613
#define DUK_SIZE_MAX          SIZE_MAX
 
614
 
 
615
#else  /* C99 types */
 
616
 
 
617
/* When C99 types are not available, we use simplistic detection to get
 
618
 * the basic 8, 16, and 32 bit types.  The fast/least types are then
 
619
 * assumed to be exactly the same for now: these could be improved per
 
620
 * platform but C99 types are very often now available.  64-bit types
 
621
 * are not defined at all now (duk_uint64_t etc).
 
622
 *
 
623
 * This detection code is necessarily a bit hacky and can provide typedefs
 
624
 * and defines that won't work correctly on some exotic platform.  It only
 
625
 * really works on 32-bit platforms.
 
626
 */
 
627
 
 
628
#undef DUK_F_HAVE_64BIT
 
629
 
 
630
#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \
 
631
    (defined(UCHAR_MAX) && (UCHAR_MAX == 255))
 
632
typedef unsigned char duk_uint8_t;
 
633
typedef signed char duk_int8_t;
 
634
#else
 
635
#error cannot detect 8-bit type
 
636
#endif
 
637
 
 
638
#if defined(USHRT_MAX) && (USHRT_MAX == 65535)
 
639
typedef unsigned short duk_uint16_t;
 
640
typedef signed short duk_int16_t;
 
641
#else
 
642
#error cannot detect 16-bit type
 
643
#endif
 
644
 
 
645
#if defined(UINT_MAX) && (UINT_MAX == 4294967295)
 
646
typedef unsigned int duk_uint32_t;
 
647
typedef signed int duk_int32_t;
 
648
#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295)
 
649
/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */
 
650
typedef unsigned long duk_uint32_t;
 
651
typedef signed long duk_int32_t;
 
652
#else
 
653
#error cannot detect 32-bit type
 
654
#endif
 
655
 
 
656
typedef duk_uint8_t duk_uint_least8_t;
 
657
typedef duk_int8_t duk_int_least8_t;
 
658
typedef duk_uint16_t duk_uint_least16_t;
 
659
typedef duk_int16_t duk_int_least16_t;
 
660
typedef duk_uint32_t duk_uint_least32_t;
 
661
typedef duk_int32_t duk_int_least32_t;
 
662
typedef duk_uint8_t duk_uint_fast8_t;
 
663
typedef duk_int8_t duk_int_fast8_t;
 
664
typedef duk_uint16_t duk_uint_fast16_t;
 
665
typedef duk_int16_t duk_int_fast16_t;
 
666
typedef duk_uint32_t duk_uint_fast32_t;
 
667
typedef duk_int32_t duk_int_fast32_t;
 
668
typedef duk_int32_t duk_intmax_t;
 
669
typedef duk_uint32_t duk_uintmax_t;
 
670
 
 
671
/* This detection is not very reliable, and only supports 32-bit platforms
 
672
 * now (64-bit platforms work if C99 types are available).
 
673
 */
 
674
#if (defined(__WORDSIZE) && (__WORDSIZE == 32)) || \
 
675
    (defined(DUK_F_MINGW) && defined(_X86_)) || \
 
676
    (defined(DUK_F_MSVC) && defined(_M_IX86))
 
677
typedef duk_int32_t duk_intptr_t;
 
678
typedef duk_uint32_t duk_uintptr_t;
 
679
#elif (defined(DUK_F_MINGW) && defined(_WIN64)) || \
 
680
      (defined(DUK_F_MSVC) && defined(_WIN64))
 
681
/* Both MinGW and MSVC have a 64-bit type. */
 
682
typedef long long duk_intptr_t;
 
683
typedef unsigned long long duk_uintptr_t;
 
684
#else
 
685
#error cannot determine intptr type
 
686
#endif
 
687
 
 
688
/* Pretend that maximum int is 32 bits. */
 
689
typedef duk_uint32_t duk_uintmax_t;
 
690
typedef duk_int32_t duk_intmax_t;
 
691
 
 
692
#define DUK_UINT8_MIN         0UL
 
693
#define DUK_UINT8_MAX         0xffUL
 
694
#define DUK_INT8_MIN          (-0x80L)
 
695
#define DUK_INT8_MAX          0x7fL
 
696
#define DUK_UINT_LEAST8_MIN   0UL
 
697
#define DUK_UINT_LEAST8_MAX   0xffUL
 
698
#define DUK_INT_LEAST8_MIN    (-0x80L)
 
699
#define DUK_INT_LEAST8_MAX    0x7fL
 
700
#define DUK_UINT_FAST8_MIN    0UL
 
701
#define DUK_UINT_FAST8_MAX    0xffUL
 
702
#define DUK_INT_FAST8_MIN     (-0x80L)
 
703
#define DUK_INT_FAST8_MAX     0x7fL
 
704
#define DUK_UINT16_MIN        0UL
 
705
#define DUK_UINT16_MAX        0xffffUL
 
706
#define DUK_INT16_MIN         (-0x8000L)
 
707
#define DUK_INT16_MAX         0x7fffL
 
708
#define DUK_UINT_LEAST16_MIN  0UL
 
709
#define DUK_UINT_LEAST16_MAX  0xffffUL
 
710
#define DUK_INT_LEAST16_MIN   (-0x8000L)
 
711
#define DUK_INT_LEAST16_MAX   0x7fffL
 
712
#define DUK_UINT_FAST16_MIN   0UL
 
713
#define DUK_UINT_FAST16_MAX   0xffffUL
 
714
#define DUK_INT_FAST16_MIN    (-0x8000L)
 
715
#define DUK_INT_FAST16_MAX    0x7fffL
 
716
#define DUK_UINT32_MIN        0UL
 
717
#define DUK_UINT32_MAX        0xffffffffUL
 
718
#define DUK_INT32_MIN         (-0x80000000L)
 
719
#define DUK_INT32_MAX         0x7fffffffL
 
720
#define DUK_UINT_LEAST32_MIN  0UL
 
721
#define DUK_UINT_LEAST32_MAX  0xffffffffUL
 
722
#define DUK_INT_LEAST32_MIN   (-0x80000000L)
 
723
#define DUK_INT_LEAST32_MAX   0x7fffffffL
 
724
#define DUK_UINT_FAST32_MIN   0UL
 
725
#define DUK_UINT_FAST32_MAX   0xffffffffUL
 
726
#define DUK_INT_FAST32_MIN    (-0x80000000L)
 
727
#define DUK_INT_FAST32_MAX    0x7fffffffL
 
728
#define DUK_UINT64_MIN        0ULL
 
729
#define DUK_UINT64_MAX        0xffffffffffffffffULL
 
730
#define DUK_INT64_MIN         (-0x8000000000000000LL)
 
731
#define DUK_INT64_MAX         0x7fffffffffffffffULL
 
732
#define DUK_UINT_LEAST64_MIN  0ULL
 
733
#define DUK_UINT_LEAST64_MAX  0xffffffffffffffffULL
 
734
#define DUK_INT_LEAST64_MIN   (-0x8000000000000000LL)
 
735
#define DUK_INT_LEAST64_MAX   0x7fffffffffffffffULL
 
736
#define DUK_UINT_FAST64_MIN   0ULL
 
737
#define DUK_UINT_FAST64_MAX   0xffffffffffffffffULL
 
738
#define DUK_INT_FAST64_MIN    (-0x8000000000000000LL)
 
739
#define DUK_INT_FAST64_MAX    0x7fffffffffffffffULL
 
740
#define DUK_UINTPTR_MIN       0UL
 
741
#define DUK_UINTPTR_MAX       0xffffffffUL
 
742
#define DUK_INTPTR_MIN        (-0x80000000L)
 
743
#define DUK_INTPTR_MAX        0x7fffffffL
 
744
#define DUK_UINTMAX_MIN       0UL
 
745
#define DUK_UINTMAX_MAX       0xffffffffUL
 
746
#define DUK_INTMAX_MIN        (-0x80000000L)
 
747
#define DUK_INTMAX_MAX        0x7fffffffL
 
748
 
 
749
/* SIZE_MAX may be missing so use an approximate value for it. */
 
750
#undef DUK_SIZE_MAX_COMPUTED
 
751
#if !defined(SIZE_MAX)
 
752
#define DUK_SIZE_MAX_COMPUTED
 
753
#define SIZE_MAX              ((size_t) (-1))
 
754
#endif
 
755
#define DUK_SIZE_MIN          0
 
756
#define DUK_SIZE_MAX          SIZE_MAX
 
757
 
 
758
#endif  /* C99 types */
 
759
 
 
760
/* The best type for an "all around int" in Duktape internals is "at least
 
761
 * 32 bit signed integer" which is fastest.  Same for unsigned type.
 
762
 */
 
763
typedef duk_int_fast32_t duk_int_t;
 
764
typedef duk_uint_fast32_t duk_uint_t;
 
765
#define DUK_INT_MIN           DUK_INT_FAST32_MIN
 
766
#define DUK_INT_MAX           DUK_INT_FAST32_MAX
 
767
#define DUK_UINT_MIN          DUK_UINT_FAST32_MIN
 
768
#define DUK_UINT_MAX          DUK_UINT_FAST32_MAX
 
769
 
 
770
/* Small integers (16 bits or more) can fall back to the 'int' type, but
 
771
 * have a typedef so they are marked "small" explicitly.
 
772
 */
 
773
typedef int duk_small_int_t;
 
774
typedef unsigned int duk_small_uint_t;
 
775
#define DUK_SMALL_INT_MIN     INT_MIN
 
776
#define DUK_SMALL_INT_MAX     INT_MAX
 
777
#define DUK_SMALL_UINT_MIN    0
 
778
#define DUK_SMALL_UINT_MAX    UINT_MAX
 
779
 
 
780
/* Codepoint type.  Must be 32 bits or more because it is used also for
 
781
 * internal codepoints.  The type is signed because negative codepoints
 
782
 * are used as internal markers (e.g. to mark EOF or missing argument).
 
783
 * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to
 
784
 * ensure duk_uint32_t casts back and forth nicely.  Almost everything
 
785
 * else uses the signed one.
 
786
 */
 
787
typedef duk_int32_t duk_codepoint_t;
 
788
typedef duk_uint32_t duk_ucodepoint_t;
 
789
 
 
790
/* IEEE double typedef. */
 
791
typedef double duk_double_t;
 
792
 
 
793
/* We're generally assuming that we're working on a platform with a 32-bit
 
794
 * address space.  If DUK_SIZE_MAX is a typecast value (which is necessary
 
795
 * if SIZE_MAX is missing), the check must be avoided because the
 
796
 * preprocessor can't do a comparison.
 
797
 */
 
798
#if !defined(DUK_SIZE_MAX)
 
799
#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX
 
800
#elif !defined(DUK_SIZE_MAX_COMPUTED)
 
801
#if DUK_SIZE_MAX < 0xffffffffUL
 
802
/* XXX: compare against a lower value; can SIZE_MAX realistically be
 
803
 * e.g. 0x7fffffffUL on a 32-bit system?
 
804
 */
 
805
#error size_t is too small
 
806
#endif
 
807
#endif
 
808
 
 
809
/* Convenience define: 32-bit pointers.  This is an important optimization
 
810
 * target (e.g. for struct sizing).
 
811
 */
 
812
#undef DUK_USE_32BIT_PTRS
 
813
#if DUK_UINTPTR_MAX <= 0xffffffffUL
 
814
#define DUK_USE_32BIT_PTRS
 
815
#endif
 
816
 
 
817
/*
 
818
 *  Check whether we should use 64-bit integers
 
819
 */
 
820
 
 
821
/* Quite incomplete now: require C99, avoid 64-bit types on VBCC because
 
822
 * they seem to misbehave.  Should use 64-bit operations at least on 64-bit
 
823
 * platforms even when C99 not available (perhaps integrate to bit type
 
824
 * detection?).
 
825
 */
 
826
#if defined(DUK_F_HAVE_64BIT) && !defined(__VBCC__)
 
827
#define DUK_USE_64BIT_OPS
 
828
#else
 
829
#undef DUK_USE_64BIT_OPS
 
830
#endif
 
831
 
 
832
/*
 
833
 *  Alignment requirement and support for unaligned accesses
 
834
 *
 
835
 *  Assume unaligned accesses are not supported unless specifically allowed
 
836
 *  in the target platform.  Some platforms may support unaligned accesses
 
837
 *  but alignment to 4 or 8 may still be desirable.
 
838
 */
 
839
 
 
840
#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
 
841
#undef DUK_USE_ALIGN_4
 
842
#undef DUK_USE_ALIGN_8
 
843
 
 
844
#if defined(DUK_F_EMSCRIPTEN)
 
845
/* Required on at least some targets, so use whenever Emscripten used,
 
846
 * regardless of compilation target.
 
847
 */
 
848
#define DUK_USE_ALIGN_8
 
849
#elif defined(DUK_F_ARM)
 
850
#define DUK_USE_ALIGN_4
 
851
#elif defined(DUK_F_MIPS)
 
852
#define DUK_USE_ALIGN_4
 
853
#elif defined(DUK_F_X86) || defined(DUK_F_X64)
 
854
#define DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
 
855
#else
 
856
/* unknown, use safe default */
 
857
#define DUK_USE_ALIGN_8
 
858
#endif
 
859
 
 
860
/* User forced alignment to 4 or 8. */
 
861
#if defined(DUK_OPT_FORCE_ALIGN)
 
862
#undef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
 
863
#undef DUK_USE_ALIGN_4
 
864
#undef DUK_USE_ALIGN_8
 
865
#if (DUK_OPT_FORCE_ALIGN == 4)
 
866
#define DUK_USE_ALIGN_4
 
867
#elif (DUK_OPT_FORCE_ALIGN == 8)
 
868
#define DUK_USE_ALIGN_8
 
869
#else
 
870
#error invalid DUK_OPT_FORCE_ALIGN value
 
871
#endif
 
872
#endif
 
873
 
 
874
/* Compiler specific hackery needed to force struct size to match aligment,
 
875
 * see e.g. duk_hbuffer.h.
 
876
 *
 
877
 * http://stackoverflow.com/questions/11130109/c-struct-size-alignment
 
878
 * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment
 
879
 */
 
880
#if defined(DUK_F_MSVC)
 
881
#define DUK_USE_PACK_MSVC_PRAGMA
 
882
#elif defined(DUK_F_GCC)
 
883
#define DUK_USE_PACK_GCC_ATTR
 
884
#elif defined(DUK_F_CLANG)
 
885
#define DUK_USE_PACK_CLANG_ATTR
 
886
#else
 
887
#define DUK_USE_PACK_DUMMY_MEMBER
 
888
#endif
 
889
 
 
890
#ifdef DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
 
891
#define DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
 
892
#else
 
893
#undef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
 
894
#endif
 
895
 
 
896
/* Object property allocation layout has implications for memory and code
 
897
 * footprint and generated code size/speed.  The best layout also depends
 
898
 * on whether the platform has alignment requirements or benefits from
 
899
 * having mostly aligned accesses.
 
900
 */
 
901
#undef DUK_USE_HOBJECT_LAYOUT_1
 
902
#undef DUK_USE_HOBJECT_LAYOUT_2
 
903
#undef DUK_USE_HOBJECT_LAYOUT_3
 
904
#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) && \
 
905
    !defined(DUK_USE_ALIGN_4) && !defined(DUK_USE_ALIGN_8)
 
906
/* On platforms without any alignment issues, layout 1 is preferable
 
907
 * because it compiles to slightly less code and provides direct access
 
908
 * to property keys.
 
909
 */
 
910
#define DUK_USE_HOBJECT_LAYOUT_1
 
911
#else
 
912
/* On other platforms use layout 2, which requires some padding but
 
913
 * is a bit more natural than layout 3 in ordering the entries.  Layout
 
914
 * 3 is currently not used.
 
915
 */
 
916
#define DUK_USE_HOBJECT_LAYOUT_2
 
917
#endif
 
918
 
 
919
/*
 
920
 *  Byte order and double memory layout detection
 
921
 *
 
922
 *  Endianness detection is a major portability hassle because the macros
 
923
 *  and headers are not standardized.  There's even variance across UNIX
 
924
 *  platforms.  Even with "standard" headers, details like underscore count
 
925
 *  varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used
 
926
 *  (Crossbridge has a single underscore, for instance).
 
927
 *
 
928
 *  The checks below are structured with this in mind: several approaches are
 
929
 *  used, and at the end we check if any of them worked.  This allows generic
 
930
 *  approaches to be tried first, and platform/compiler specific hacks tried
 
931
 *  last.  As a last resort, the user can force a specific endianness, as it's
 
932
 *  not likely that automatic detection will work on the most exotic platforms.
 
933
 *
 
934
 *  Duktape supports little and big endian machines.  There's also support
 
935
 *  for a hybrid used by some ARM machines where integers are little endian
 
936
 *  but IEEE double values use a mixed order (12345678 -> 43218765).  This
 
937
 *  byte order for doubles is referred to as "mixed endian".
 
938
 */
 
939
 
 
940
#undef DUK_F_BYTEORDER
 
941
#undef DUK_USE_BYTEORDER_FORCED
 
942
 
 
943
/* DUK_F_BYTEORDER is set as an intermediate value when detection
 
944
 * succeeds, to one of:
 
945
 *   1 = little endian
 
946
 *   2 = mixed (arm hybrid) endian
 
947
 *   3 = big endian
 
948
 */
 
949
 
 
950
/* For custom platforms allow user to define byteorder explicitly.
 
951
 * Since endianness headers are not standardized, this is a useful
 
952
 * workaround for custom platforms for which endianness detection
 
953
 * is not directly supported.  Perhaps custom hardware is used and
 
954
 * user cannot submit upstream patches.
 
955
 */
 
956
#if defined(DUK_OPT_FORCE_BYTEORDER)
 
957
#if (DUK_OPT_FORCE_BYTEORDER == 1)
 
958
#define DUK_F_BYTEORDER 1
 
959
#elif (DUK_OPT_FORCE_BYTEORDER == 2)
 
960
#define DUK_F_BYTEORDER 2
 
961
#elif (DUK_OPT_FORCE_BYTEORDER == 3)
 
962
#define DUK_F_BYTEORDER 3
 
963
#else
 
964
#error invalid DUK_OPT_FORCE_BYTEORDER value
 
965
#endif
 
966
#define DUK_USE_BYTEORDER_FORCED
 
967
#endif  /* DUK_OPT_FORCE_BYTEORDER */
 
968
 
 
969
/* More or less standard endianness predefines provided by header files.
 
970
 * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER
 
971
 * will be big endian, see: http://lists.mysql.com/internals/443.
 
972
 */
 
973
#if !defined(DUK_F_BYTEORDER)
 
974
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \
 
975
    defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \
 
976
    defined(__LITTLE_ENDIAN__)
 
977
/* Integer little endian */
 
978
#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \
 
979
    defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN)
 
980
#define DUK_F_BYTEORDER 1
 
981
#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \
 
982
      defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN)
 
983
#define DUK_F_BYTEORDER 2
 
984
#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER)
 
985
/* Float word order not known, assume not a hybrid. */
 
986
#define DUK_F_BYTEORDER 1
 
987
#else
 
988
/* byte order is little endian but cannot determine IEEE double word order */
 
989
#endif  /* float word order */
 
990
#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \
 
991
      defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \
 
992
      defined(__BIG_ENDIAN__)
 
993
/* Integer big endian */
 
994
#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \
 
995
    defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN)
 
996
#define DUK_F_BYTEORDER 3
 
997
#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER)
 
998
/* Float word order not known, assume not a hybrid. */
 
999
#define DUK_F_BYTEORDER 3
 
1000
#else
 
1001
/* byte order is big endian but cannot determine IEEE double word order */
 
1002
#endif  /* float word order */
 
1003
#else
 
1004
/* cannot determine byte order */
 
1005
#endif  /* integer byte order */
 
1006
#endif  /* !defined(DUK_F_BYTEORDER) */
 
1007
 
 
1008
/* GCC and Clang provide endianness defines as built-in predefines, with
 
1009
 * leading and trailing double underscores (e.g. __BYTE_ORDER__).  See
 
1010
 * output of "make gccpredefs" and "make clangpredefs".  Clang doesn't
 
1011
 * seem to provide __FLOAT_WORD_ORDER__.
 
1012
 * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
 
1013
 */
 
1014
#if !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__)
 
1015
#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
 
1016
/* Integer little endian */
 
1017
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
 
1018
    (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
 
1019
#define DUK_F_BYTEORDER 1
 
1020
#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
 
1021
      (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
 
1022
#define DUK_F_BYTEORDER 2
 
1023
#elif !defined(__FLOAT_WORD_ORDER__)
 
1024
/* Float word order not known, assume not a hybrid. */
 
1025
#define DUK_F_BYTEORDER 1
 
1026
#else
 
1027
/* byte order is little endian but cannot determine IEEE double word order */
 
1028
#endif  /* float word order */
 
1029
#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
 
1030
/* Integer big endian */
 
1031
#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
 
1032
    (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
 
1033
#define DUK_F_BYTEORDER 3
 
1034
#elif !defined(__FLOAT_WORD_ORDER__)
 
1035
/* Float word order not known, assume not a hybrid. */
 
1036
#define DUK_F_BYTEORDER 3
 
1037
#else
 
1038
/* byte order is big endian but cannot determine IEEE double word order */
 
1039
#endif  /* float word order */
 
1040
#else
 
1041
/* cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit
 
1042
 * integer ordering and is not relevant
 
1043
 */
 
1044
#endif  /* integer byte order */
 
1045
#endif  /* !defined(DUK_F_BYTEORDER) && defined(__BYTE_ORDER__) */
 
1046
 
 
1047
/* Atari ST TOS */
 
1048
#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_TOS)
 
1049
#define DUK_F_BYTEORDER 3
 
1050
#endif
 
1051
 
 
1052
/* AmigaOS on M68k */
 
1053
#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_AMIGAOS)
 
1054
#if defined(DUK_F_M68K)
 
1055
#define DUK_F_BYTEORDER 3
 
1056
#endif
 
1057
#endif
 
1058
 
 
1059
/* On Windows, assume we're little endian.  Even Itanium which has a
 
1060
 * configurable endianness runs little endian in Windows.
 
1061
 */
 
1062
#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_WINDOWS)
 
1063
/* XXX: verify that Windows on ARM is little endian for floating point
 
1064
 * values too.
 
1065
 */
 
1066
#define DUK_F_BYTEORDER 1
 
1067
#endif  /* Windows */
 
1068
 
 
1069
/* Crossbridge should work with the standard byteorder #ifdefs.  It doesn't
 
1070
 * provide _FLOAT_WORD_ORDER but the standard approach now covers that case
 
1071
 * too.  This has been left here just in case.
 
1072
 */
 
1073
#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_FLASHPLAYER)
 
1074
#define DUK_F_BYTEORDER 1
 
1075
#endif
 
1076
 
 
1077
/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__:
 
1078
 *  $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
 
1079
 *  67:#define __LITTLEENDIAN__ 1
 
1080
 *  $ /opt/qnx650/host/linux/x86/usr/bin/mips-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
 
1081
 *  81:#define __BIGENDIAN__ 1
 
1082
 *  $ /opt/qnx650/host/linux/x86/usr/bin/arm-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
 
1083
 *  70:#define __LITTLEENDIAN__ 1
 
1084
 */
 
1085
#if !defined(DUK_F_BYTEORDER) && defined(DUK_F_QNX)
 
1086
/* XXX: ARM hybrid? */
 
1087
#if defined(__LITTLEENDIAN__)
 
1088
#define DUK_F_BYTEORDER 1
 
1089
#elif defined(__BIGENDIAN__)
 
1090
#define DUK_F_BYTEORDER 3
 
1091
#endif
 
1092
#endif
 
1093
 
 
1094
/* Check whether or not byte order detection worked based on the intermediate
 
1095
 * define, and define final values.  If detection failed, #error out.
 
1096
 */
 
1097
#if defined(DUK_F_BYTEORDER)
 
1098
#if (DUK_F_BYTEORDER == 1)
 
1099
#define DUK_USE_INTEGER_LE
 
1100
#define DUK_USE_DOUBLE_LE
 
1101
#elif (DUK_F_BYTEORDER == 2)
 
1102
#define DUK_USE_INTEGER_LE  /* integer endianness is little on purpose */
 
1103
#define DUK_USE_DOUBLE_ME
 
1104
#elif (DUK_F_BYTEORDER == 3)
 
1105
#define DUK_USE_INTEGER_BE
 
1106
#define DUK_USE_DOUBLE_BE
 
1107
#else
 
1108
#error unsupported: byte order detection failed (internal error, should not happen)
 
1109
#endif  /* byte order */
 
1110
#else
 
1111
#error unsupported: byte order detection failed
 
1112
#endif  /* defined(DUK_F_BYTEORDER) */
 
1113
 
 
1114
/*
 
1115
 *  Check whether or not a packed duk_tval representation is possible.
 
1116
 *  What's basically required is that pointers are 32-bit values
 
1117
 *  (sizeof(void *) == 4).  Best effort check, not always accurate.
 
1118
 */
 
1119
 
 
1120
#undef DUK_USE_PACKED_TVAL_POSSIBLE
 
1121
#if defined(UINTPTR_MAX) && (UINTPTR_MAX <= 0xffffffffUL)
 
1122
/* strict C99 check */
 
1123
#define DUK_USE_PACKED_TVAL_POSSIBLE
 
1124
#endif
 
1125
 
 
1126
#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED)
 
1127
#if DUK_SIZE_MAX <= 0xffffffffUL
 
1128
#define DUK_USE_PACKED_TVAL_POSSIBLE
 
1129
#endif
 
1130
#endif
 
1131
 
 
1132
#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE) && defined(DUK_F_M68K)
 
1133
#define DUK_USE_PACKED_TVAL_POSSIBLE
 
1134
#endif
 
1135
 
 
1136
/* With Emscripten, force unpacked duk_tval just to be safe. */
 
1137
#if defined(DUK_F_EMSCRIPTEN) && defined(DUK_USE_PACKED_TVAL_POSSIBLE)
 
1138
#undef DUK_USE_PACKED_TVAL_POSSIBLE
 
1139
#endif
 
1140
 
 
1141
/* GCC/clang inaccurate math would break compliance and probably duk_tval,
 
1142
 * so refuse to compile.  Relax this if -ffast-math is tested to work.
 
1143
 */
 
1144
#if defined(__FAST_MATH__)
 
1145
#error __FAST_MATH__ defined, refusing to compile
 
1146
#endif
 
1147
 
 
1148
/*
 
1149
 *  Detection of double constants and math related functions.  Availability
 
1150
 *  of constants and math functions is a significant porting concern.
 
1151
 *
 
1152
 *  INFINITY/HUGE_VAL is problematic on GCC-3.3: it causes an overflow warning
 
1153
 *  and there is no pragma in GCC-3.3 to disable it.  Using __builtin_inf()
 
1154
 *  avoids this problem for some reason.
 
1155
 */
 
1156
 
 
1157
#define DUK_DOUBLE_2TO32     4294967296.0
 
1158
#define DUK_DOUBLE_2TO31     2147483648.0
 
1159
 
 
1160
#undef DUK_USE_COMPUTED_INFINITY
 
1161
#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600)
 
1162
/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */
 
1163
#define DUK_DOUBLE_INFINITY  (__builtin_inf())
 
1164
#elif defined(INFINITY)
 
1165
#define DUK_DOUBLE_INFINITY  ((double) INFINITY)
 
1166
#elif !defined(__VBCC__) && !defined(_MSC_VER)
 
1167
#define DUK_DOUBLE_INFINITY  (1.0 / 0.0)
 
1168
#else
 
1169
/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity.
 
1170
 * Use a computed infinity (initialized when a heap is created at the
 
1171
 * latest).
 
1172
 */
 
1173
extern double duk_computed_infinity;
 
1174
#define DUK_USE_COMPUTED_INFINITY
 
1175
#define DUK_DOUBLE_INFINITY  duk_computed_infinity
 
1176
#endif
 
1177
 
 
1178
#undef DUK_USE_COMPUTED_NAN
 
1179
#if defined(NAN)
 
1180
#define DUK_DOUBLE_NAN       NAN
 
1181
#elif !defined(__VBCC__) && !defined(_MSC_VER)
 
1182
#define DUK_DOUBLE_NAN       (0.0 / 0.0)
 
1183
#else
 
1184
/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN.
 
1185
 * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error.
 
1186
 * Use a computed NaN (initialized when a heap is created at the
 
1187
 * latest).
 
1188
 */
 
1189
extern double duk_computed_nan;
 
1190
#define DUK_USE_COMPUTED_NAN
 
1191
#define DUK_DOUBLE_NAN       duk_computed_nan
 
1192
#endif
 
1193
 
 
1194
/* Many platforms are missing fpclassify() and friends, so use replacements
 
1195
 * if necessary.  The replacement constants (FP_NAN etc) can be anything but
 
1196
 * match Linux constants now.
 
1197
 */
 
1198
#undef DUK_USE_REPL_FPCLASSIFY
 
1199
#undef DUK_USE_REPL_SIGNBIT
 
1200
#undef DUK_USE_REPL_ISFINITE
 
1201
#undef DUK_USE_REPL_ISNAN
 
1202
#undef DUK_USE_REPL_ISINF
 
1203
 
 
1204
/* complex condition broken into separate parts */
 
1205
#undef DUK_F_USE_REPL_ALL
 
1206
#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \
 
1207
      defined(FP_SUBNORMAL) && defined(FP_NORMAL))
 
1208
/* missing some obvious constants */
 
1209
#define DUK_F_USE_REPL_ALL
 
1210
#elif defined(DUK_F_AMIGAOS) && defined(__VBCC__)
 
1211
/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue) */
 
1212
#define DUK_F_USE_REPL_ALL
 
1213
#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG)
 
1214
/* Placeholder fix for (detection is wider than necessary):
 
1215
 * http://llvm.org/bugs/show_bug.cgi?id=17788
 
1216
 */
 
1217
#define DUK_F_USE_REPL_ALL
 
1218
#endif
 
1219
 
 
1220
#if defined(DUK_F_USE_REPL_ALL)
 
1221
#define DUK_USE_REPL_FPCLASSIFY
 
1222
#define DUK_USE_REPL_SIGNBIT
 
1223
#define DUK_USE_REPL_ISFINITE
 
1224
#define DUK_USE_REPL_ISNAN
 
1225
#define DUK_USE_REPL_ISINF
 
1226
#define DUK_FPCLASSIFY       duk_repl_fpclassify
 
1227
#define DUK_SIGNBIT          duk_repl_signbit
 
1228
#define DUK_ISFINITE         duk_repl_isfinite
 
1229
#define DUK_ISNAN            duk_repl_isnan
 
1230
#define DUK_ISINF            duk_repl_isinf
 
1231
#define DUK_FP_NAN           0
 
1232
#define DUK_FP_INFINITE      1
 
1233
#define DUK_FP_ZERO          2
 
1234
#define DUK_FP_SUBNORMAL     3
 
1235
#define DUK_FP_NORMAL        4
 
1236
#else
 
1237
#define DUK_FPCLASSIFY       fpclassify
 
1238
#define DUK_SIGNBIT          signbit
 
1239
#define DUK_ISFINITE         isfinite
 
1240
#define DUK_ISNAN            isnan
 
1241
#define DUK_ISINF            isinf
 
1242
#define DUK_FP_NAN           FP_NAN
 
1243
#define DUK_FP_INFINITE      FP_INFINITE
 
1244
#define DUK_FP_ZERO          FP_ZERO
 
1245
#define DUK_FP_SUBNORMAL     FP_SUBNORMAL
 
1246
#define DUK_FP_NORMAL        FP_NORMAL
 
1247
#endif
 
1248
 
 
1249
#if defined(DUK_F_USE_REPL_ALL)
 
1250
#undef DUK_F_USE_REPL_ALL
 
1251
#endif
 
1252
 
 
1253
/* Some math functions are C99 only.  This is also an issue with some
 
1254
 * embedded environments using uclibc where uclibc has been configured
 
1255
 * not to provide some functions.  For now, use replacements whenever
 
1256
 * using uclibc.
 
1257
 */
 
1258
#if defined(DUK_F_C99) && \
 
1259
    !defined(__UCLIBC__) /* uclibc may be missing these */ && \
 
1260
    !(defined(DUK_F_AMIGAOS) && defined(__VBCC__)) /* vbcc + AmigaOS may be missing these */
 
1261
#define DUK_USE_MATH_FMIN
 
1262
#define DUK_USE_MATH_FMAX
 
1263
#define DUK_USE_MATH_ROUND
 
1264
#else
 
1265
#undef DUK_USE_MATH_FMIN
 
1266
#undef DUK_USE_MATH_FMAX
 
1267
#undef DUK_USE_MATH_ROUND
 
1268
#endif
 
1269
 
 
1270
/* These functions don't currently need replacement but are wrapped for
 
1271
 * completeness.  Because these are used as function pointers, they need
 
1272
 * to be defined as concrete C functions (not macros).
 
1273
 */
 
1274
#define DUK_FABS             fabs
 
1275
#define DUK_FMIN             fmin
 
1276
#define DUK_FMAX             fmax
 
1277
#define DUK_FLOOR            floor
 
1278
#define DUK_CEIL             ceil
 
1279
#define DUK_FMOD             fmod
 
1280
#define DUK_POW              pow
 
1281
#define DUK_ACOS             acos
 
1282
#define DUK_ASIN             asin
 
1283
#define DUK_ATAN             atan
 
1284
#define DUK_ATAN2            atan2
 
1285
#define DUK_SIN              sin
 
1286
#define DUK_COS              cos
 
1287
#define DUK_TAN              tan
 
1288
#define DUK_EXP              exp
 
1289
#define DUK_LOG              log
 
1290
#define DUK_SQRT             sqrt
 
1291
 
 
1292
/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics,
 
1293
 * see test-bug-netbsd-math-pow.js.  Use NetBSD specific workaround.
 
1294
 * (This might be a wider problem; if so, generalize the define name.)
 
1295
 */
 
1296
#undef DUK_USE_POW_NETBSD_WORKAROUND
 
1297
#if defined(DUK_F_NETBSD)
 
1298
#define DUK_USE_POW_NETBSD_WORKAROUND
 
1299
#endif
 
1300
 
 
1301
/* Rely as little as possible on compiler behavior for NaN comparison,
 
1302
 * signed zero handling, etc.  Currently never activated but may be needed
 
1303
 * for broken compilers.
 
1304
 */
 
1305
#undef DUK_USE_PARANOID_MATH
 
1306
 
 
1307
/*
 
1308
 *  ANSI C string/memory function wrapper defines to allow easier workarounds.
 
1309
 *  Also convenience macros like DUK_MEMZERO which may be mapped to existing
 
1310
 *  platform function to zero memory (like the deprecated bzero).
 
1311
 *
 
1312
 *  For instance, some platforms don't support zero-size memcpy correctly,
 
1313
 *  some arcane uclibc versions have a buggy memcpy (but working memmove)
 
1314
 *  and so on.  Such broken platforms can be dealt with here.
 
1315
 */
 
1316
 
 
1317
typedef FILE duk_file;
 
1318
#define DUK_STDIN       stdin
 
1319
#define DUK_STDOUT      stdout
 
1320
#define DUK_STDERR      stderr
 
1321
 
 
1322
/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h
 
1323
 * (which is unfortunately named).
 
1324
 */
 
1325
#define DUK_ANSI_MALLOC      malloc
 
1326
#define DUK_ANSI_REALLOC     realloc
 
1327
#define DUK_ANSI_CALLOC      calloc
 
1328
#define DUK_ANSI_FREE        free
 
1329
 
 
1330
/* Old uclibcs have a broken memcpy so use memmove instead (this is overly
 
1331
 * wide now on purpose):
 
1332
 * http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html
 
1333
 */
 
1334
#if defined(__UCLIBC__)
 
1335
#define DUK_MEMCPY       memmove
 
1336
#else
 
1337
#define DUK_MEMCPY       memcpy
 
1338
#endif
 
1339
 
 
1340
#define DUK_MEMMOVE      memmove
 
1341
#define DUK_MEMCMP       memcmp
 
1342
#define DUK_MEMSET       memset
 
1343
#define DUK_STRLEN       strlen
 
1344
#define DUK_STRCMP       strcmp
 
1345
#define DUK_STRNCMP      strncmp
 
1346
#define DUK_PRINTF       printf
 
1347
#define DUK_FPRINTF      fprintf
 
1348
#define DUK_SPRINTF      sprintf
 
1349
#if defined(DUK_F_MSVC)
 
1350
/* _snprintf() does NOT NUL terminate on truncation, but Duktape code never
 
1351
 * assumes that.
 
1352
 * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
 
1353
 */
 
1354
#define DUK_SNPRINTF     _snprintf
 
1355
#else
 
1356
#define DUK_SNPRINTF     snprintf
 
1357
#endif
 
1358
#define DUK_VSPRINTF     vsprintf
 
1359
#define DUK_VSNPRINTF    vsnprintf
 
1360
#define DUK_SSCANF       sscanf
 
1361
#define DUK_VSSCANF      vsscanf
 
1362
#define DUK_FOPEN        fopen
 
1363
#define DUK_FCLOSE       fclose
 
1364
#define DUK_FREAD        fread
 
1365
#define DUK_FWRITE       fwrite
 
1366
#define DUK_FSEEK        fseek
 
1367
#define DUK_FTELL        ftell
 
1368
#define DUK_FFLUSH       fflush
 
1369
#define DUK_FPUTC        fputc
 
1370
 
 
1371
#define DUK_MEMZERO(p,n) \
 
1372
        DUK_MEMSET((p), 0, (n))
 
1373
 
 
1374
/*
 
1375
 *  Miscellaneous ANSI C or other platform wrappers.
 
1376
 */
 
1377
 
 
1378
#define DUK_ABORT        abort
 
1379
#define DUK_EXIT         exit
 
1380
#define DUK_SETJMP       setjmp
 
1381
#define DUK_LONGJMP      longjmp
 
1382
 
 
1383
/*
 
1384
 *  Macro hackery to convert e.g. __LINE__ to a string without formatting,
 
1385
 *  see: http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string
 
1386
 */
 
1387
 
 
1388
#define DUK_F_STRINGIFY_HELPER(x)  #x
 
1389
#define DUK_MACRO_STRINGIFY(x)  DUK_F_STRINGIFY_HELPER(x)
 
1390
 
 
1391
/*
 
1392
 *  Cause segfault macro.
 
1393
 *
 
1394
 *  This is optionally used by panic handling to cause the program to segfault
 
1395
 *  (instead of e.g. abort()) on panic.  Valgrind will then indicate the C
 
1396
 *  call stack leading to the panic.
 
1397
 */
 
1398
 
 
1399
#define DUK_CAUSE_SEGFAULT()  do { \
 
1400
                *((uint32_t *) NULL) = (uint32_t) 0xdeadbeefUL; \
 
1401
        } while (0)
 
1402
 
 
1403
/*
 
1404
 *  Macro for suppressing warnings for potentially unreferenced variables.
 
1405
 *  The variables can be actually unreferenced or unreferenced in some
 
1406
 *  specific cases only; for instance, if a variable is only debug printed,
 
1407
 *  it is unreferenced when debug printing is disabled.
 
1408
 *
 
1409
 *  (Introduced here because it's potentially compiler specific.)
 
1410
 */
 
1411
 
 
1412
#define DUK_UNREF(x)  do { \
 
1413
                (void) (x); \
 
1414
        } while (0)
 
1415
 
 
1416
/*
 
1417
 *  Macro for declaring a 'noreturn' function, detection in duktape.h.
 
1418
 */
 
1419
 
 
1420
#define DUK_NORETURN(decl) DUK_API_NORETURN(decl)
 
1421
 
 
1422
/*
 
1423
 *  Macro for stating that a certain line cannot be reached.
 
1424
 *
 
1425
 *  http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Other-Builtins.html#Other-Builtins
 
1426
 *  http://clang.llvm.org/docs/LanguageExtensions.html
 
1427
 */
 
1428
 
 
1429
#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500)
 
1430
/* since gcc-4.5 */
 
1431
#define DUK_UNREACHABLE()  do { __builtin_unreachable(); } while(0)
 
1432
#elif defined(__clang__) && defined(__has_builtin)
 
1433
#if __has_builtin(__builtin_unreachable)
 
1434
/* same as gcc */
 
1435
#define DUK_UNREACHABLE()  do { __builtin_unreachable(); } while(0)
 
1436
#endif
 
1437
#else
 
1438
/* unknown */
 
1439
#endif
 
1440
 
 
1441
#if !defined(DUK_UNREACHABLE)
 
1442
/* Don't know how to declare unreachable point, so don't do it; this
 
1443
 * may cause some spurious compilation warnings (e.g. "variable used
 
1444
 * uninitialized").
 
1445
 */
 
1446
#define DUK_UNREACHABLE()  /* unreachable */
 
1447
#endif
 
1448
 
 
1449
/*
 
1450
 *  Likely and unlikely branches.  Using these is not at all a clear cut case,
 
1451
 *  so the selection is a two-step process: (1) DUK_USE_BRANCH_HINTS is set
 
1452
 *  if the architecture, compiler etc make it useful to use the hints, and (2)
 
1453
 *  a separate check determines how to do them.
 
1454
 *
 
1455
 *  These macros expect the argument to be a relational expression with an
 
1456
 *  integer value.  If used with pointers, you should use an explicit check
 
1457
 *  like:
 
1458
 *
 
1459
 *    if (DUK_LIKELY(ptr != NULL)) { ... }
 
1460
 *
 
1461
 *  instead of:
 
1462
 *
 
1463
 *    if (DUK_LIKELY(ptr)) { ... }
 
1464
 *
 
1465
 *  http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html  (__builtin_expect)
 
1466
 */
 
1467
 
 
1468
/* pretty much a placeholder now */
 
1469
#if defined(DUK_F_GCC)
 
1470
#define DUK_USE_BRANCH_HINTS
 
1471
#elif defined(DUK_F_CLANG)
 
1472
#define DUK_USE_BRANCH_HINTS
 
1473
#else
 
1474
#undef DUK_USE_BRANCH_HINTS
 
1475
#endif
 
1476
 
 
1477
#if defined(DUK_USE_BRANCH_HINTS)
 
1478
#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERISON >= 40500)
 
1479
/* GCC: test not very accurate; enable only in relatively recent builds
 
1480
 * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html)
 
1481
 */
 
1482
#define DUK_LIKELY(x)    __builtin_expect((x), 1)
 
1483
#define DUK_UNLIKELY(x)  __builtin_expect((x), 0)
 
1484
#elif defined(DUK_F_CLANG)
 
1485
#define DUK_LIKELY(x)    __builtin_expect((x), 1)
 
1486
#define DUK_UNLIKELY(x)  __builtin_expect((x), 0)
 
1487
#endif
 
1488
#endif  /* DUK_USE_BRANCH_HINTS */
 
1489
 
 
1490
#if !defined(DUK_LIKELY)
 
1491
#define DUK_LIKELY(x)    (x)
 
1492
#endif
 
1493
#if !defined(DUK_UNLIKELY)
 
1494
#define DUK_UNLIKELY(x)  (x)
 
1495
#endif
 
1496
 
 
1497
/*
 
1498
 *  __FILE__, __LINE__, __func__ are wrapped.  Especially __func__ is a
 
1499
 *  problem because it is not available even in some compilers which try
 
1500
 *  to be C99 compatible (e.g. VBCC with -c99 option).
 
1501
 */
 
1502
 
 
1503
#define DUK_FILE_MACRO  __FILE__
 
1504
 
 
1505
#define DUK_LINE_MACRO  __LINE__
 
1506
 
 
1507
#if !defined(__VBCC__) && !defined(_MSC_VER)
 
1508
#define DUK_FUNC_MACRO  __func__
 
1509
#else
 
1510
#define DUK_FUNC_MACRO  "unknown"
 
1511
#endif
 
1512
 
 
1513
/*
 
1514
 *  Architecture string, human readable value exposed in Duktape.env
 
1515
 */
 
1516
 
 
1517
#if defined(DUK_F_X86)
 
1518
#define DUK_USE_ARCH_STRING "x86"
 
1519
#elif defined(DUK_F_X64)
 
1520
#define DUK_USE_ARCH_STRING "x64"
 
1521
#elif defined(DUK_F_ARM)
 
1522
#define DUK_USE_ARCH_STRING "arm"
 
1523
#elif defined(DUK_F_MIPS)
 
1524
#define DUK_USE_ARCH_STRING "mips"
 
1525
#elif defined(DUK_F_M68K)
 
1526
#define DUK_USE_ARCH_STRING "m68k"
 
1527
#elif defined(DUK_F_FLASHPLAYER)
 
1528
#define DUK_USE_ARCH_STRING "flashplayer"
 
1529
#elif defined(DUK_F_EMSCRIPTEN)
 
1530
#define DUK_USE_ARCH_STRING "emscripten"
 
1531
#else
 
1532
#define DUK_USE_ARCH_STRING "unknown"
 
1533
#endif
 
1534
 
 
1535
/* 
 
1536
 *  Tagged type representation (duk_tval)
 
1537
 */
 
1538
 
 
1539
#undef DUK_USE_PACKED_TVAL
 
1540
#undef DUK_USE_FULL_TVAL
 
1541
 
 
1542
#if defined(DUK_USE_PACKED_TVAL_POSSIBLE) && !defined(DUK_OPT_NO_PACKED_TVAL)
 
1543
#define DUK_USE_PACKED_TVAL
 
1544
#undef DUK_USE_FULL_TVAL
 
1545
#endif
 
1546
 
 
1547
/*
 
1548
 *  Memory management options
 
1549
 */
 
1550
 
 
1551
#define DUK_USE_REFERENCE_COUNTING
 
1552
#define DUK_USE_DOUBLE_LINKED_HEAP
 
1553
#define DUK_USE_MARK_AND_SWEEP
 
1554
#define DUK_USE_MS_STRINGTABLE_RESIZE
 
1555
#undef DUK_USE_GC_TORTURE
 
1556
 
 
1557
#if defined(DUK_OPT_NO_REFERENCE_COUNTING)
 
1558
#undef DUK_USE_REFERENCE_COUNTING
 
1559
#undef DUK_USE_DOUBLE_LINKED_HEAP
 
1560
/* XXX: undef DUK_USE_MS_STRINGTABLE_RESIZE as it is more expensive
 
1561
 * with more frequent mark-and-sweeps?
 
1562
 */
 
1563
#endif
 
1564
 
 
1565
#if defined(DUK_OPT_NO_MARK_AND_SWEEP)
 
1566
#undef DUK_USE_MARK_AND_SWEEP
 
1567
#endif
 
1568
 
 
1569
#if defined(DUK_USE_MARK_AND_SWEEP)
 
1570
#define DUK_USE_VOLUNTARY_GC
 
1571
#if defined(DUK_OPT_NO_VOLUNTARY_GC)
 
1572
#undef DUK_USE_VOLUNTARY_GC
 
1573
#endif
 
1574
#endif
 
1575
 
 
1576
#if !defined(DUK_USE_MARK_AND_SWEEP) && !defined(DUK_USE_REFERENCE_COUNTING)
 
1577
#error must have either mark-and-sweep or reference counting enabled
 
1578
#endif
 
1579
 
 
1580
#if defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE)
 
1581
#undef DUK_USE_MS_STRINGTABLE_RESIZE
 
1582
#endif
 
1583
 
 
1584
#if defined(DUK_OPT_GC_TORTURE)
 
1585
#define DUK_USE_GC_TORTURE
 
1586
#endif
 
1587
 
 
1588
/*
 
1589
 *  Error handling options
 
1590
 */
 
1591
 
 
1592
#define DUK_USE_AUGMENT_ERROR_CREATE
 
1593
#define DUK_USE_AUGMENT_ERROR_THROW
 
1594
#define DUK_USE_TRACEBACKS
 
1595
#define DUK_USE_ERRCREATE
 
1596
#define DUK_USE_ERRTHROW
 
1597
 
 
1598
#define DUK_USE_VERBOSE_ERRORS
 
1599
 
 
1600
#if defined(DUK_OPT_NO_AUGMENT_ERRORS)
 
1601
#undef DUK_USE_AUGMENT_ERROR_CREATE
 
1602
#undef DUK_USE_AUGMENT_ERROR_THROW
 
1603
#undef DUK_USE_TRACEBACKS
 
1604
#undef DUK_USE_ERRCREATE
 
1605
#undef DUK_USE_ERRTHROW
 
1606
#elif defined(DUK_OPT_NO_TRACEBACKS)
 
1607
#undef DUK_USE_TRACEBACKS
 
1608
#endif
 
1609
 
 
1610
#if defined(DUK_OPT_NO_VERBOSE_ERRORS)
 
1611
#undef DUK_USE_VERBOSE_ERRORS
 
1612
#endif
 
1613
 
 
1614
#if defined(DUK_USE_TRACEBACKS)
 
1615
#if defined(DUK_OPT_TRACEBACK_DEPTH)
 
1616
#define DUK_USE_TRACEBACK_DEPTH  DUK_OPT_TRACEBACK_DEPTH
 
1617
#else
 
1618
#define DUK_USE_TRACEBACK_DEPTH  10
 
1619
#endif
 
1620
#endif
 
1621
 
 
1622
/* Include messages in executor internal errors. */
 
1623
#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
 
1624
 
 
1625
/*
 
1626
 *  Execution and debugger options
 
1627
 */
 
1628
 
 
1629
#define DUK_USE_INTERRUPT_COUNTER
 
1630
#if defined(DUK_OPT_NO_INTERRUPT_COUNTER)
 
1631
#undef DUK_USE_INTERRUPT_COUNTER
 
1632
#endif
 
1633
 
 
1634
/*
 
1635
 *  Debug printing and assertion options
 
1636
 */
 
1637
 
 
1638
#undef DUK_USE_DEBUG
 
1639
#undef DUK_USE_DDEBUG
 
1640
#undef DUK_USE_DDDEBUG
 
1641
#undef DUK_USE_DPRINT_RDTSC
 
1642
#undef DUK_USE_ASSERTIONS
 
1643
 
 
1644
#if defined(DUK_OPT_DEBUG)
 
1645
#define DUK_USE_DEBUG
 
1646
#endif
 
1647
#if defined(DUK_OPT_DDEBUG)
 
1648
#define DUK_USE_DDEBUG
 
1649
#endif
 
1650
#if defined(DUK_OPT_DDDEBUG)
 
1651
#define DUK_USE_DDDEBUG
 
1652
#endif
 
1653
 
 
1654
#undef DUK_USE_DPRINT_COLORS
 
1655
#if defined(DUK_OPT_DPRINT_COLORS)
 
1656
#define DUK_USE_DPRINT_COLORS
 
1657
#endif
 
1658
 
 
1659
#if defined(DUK_RDTSC_AVAILABLE) && defined(DUK_OPT_DPRINT_RDTSC)
 
1660
#define DUK_USE_DPRINT_RDTSC
 
1661
#else
 
1662
#undef DUK_USE_DPRINT_RDTSC
 
1663
#endif
 
1664
 
 
1665
#if defined(DUK_OPT_ASSERTIONS)
 
1666
#define DUK_USE_ASSERTIONS
 
1667
#endif
 
1668
 
 
1669
/* The static buffer for debug printing is quite large by default, so there
 
1670
 * is an option to shrink it manually for constrained builds.
 
1671
 */
 
1672
#if defined(DUK_OPT_DEBUG_BUFSIZE)
 
1673
#define DUK_USE_DEBUG_BUFSIZE  DUK_OPT_DEBUG_BUFSIZE
 
1674
#else
 
1675
#define DUK_USE_DEBUG_BUFSIZE  65536
 
1676
#endif
 
1677
 
 
1678
/*
 
1679
 *  Ecmascript features / compliance options
 
1680
 */
 
1681
 
 
1682
#define DUK_USE_REGEXP_SUPPORT
 
1683
#if defined(DUK_OPT_NO_REGEXP_SUPPORT)
 
1684
#undef DUK_USE_REGEXP_SUPPORT
 
1685
#endif
 
1686
 
 
1687
#undef DUK_USE_STRICT_UTF8_SOURCE
 
1688
#if defined(DUK_OPT_STRICT_UTF8_SOURCE)
 
1689
#define DUK_USE_STRICT_UTF8_SOURCE
 
1690
#endif
 
1691
 
 
1692
#define DUK_USE_OCTAL_SUPPORT
 
1693
#if defined(DUK_OPT_NO_OCTAL_SUPPORT)
 
1694
#undef DUK_USE_OCTAL_SUPPORT
 
1695
#endif
 
1696
 
 
1697
#define DUK_USE_SOURCE_NONBMP
 
1698
#if defined(DUK_OPT_NO_SOURCE_NONBMP)
 
1699
#undef DUK_USE_SOURCE_NONBMP
 
1700
#endif
 
1701
 
 
1702
#define DUK_USE_BROWSER_LIKE
 
1703
#if defined(DUK_OPT_NO_BROWSER_LIKE)
 
1704
#undef DUK_USE_BROWSER_LIKE
 
1705
#endif
 
1706
 
 
1707
#define DUK_USE_SECTION_B
 
1708
#if defined(DUK_OPT_NO_SECTION_B)
 
1709
#undef DUK_USE_SECTION_B
 
1710
#endif
 
1711
 
 
1712
/* Treat function statements (function declarations outside top level of
 
1713
 * Program or FunctionBody) same as normal function declarations.  This is
 
1714
 * also V8 behavior.  See test-dev-func-decl-outside-top.js.
 
1715
 */ 
 
1716
#define DUK_USE_FUNC_STMT
 
1717
#if defined(DUK_OPT_NO_FUNC_STMT)
 
1718
#undef DUK_USE_FUNC_STMT
 
1719
#endif
 
1720
 
 
1721
/* Array.prototype.splice() non-standard but real world compatible behavior
 
1722
 * when deleteCount is omitted.
 
1723
 */
 
1724
#define DUK_USE_ARRAY_SPLICE_NONSTD_DELCOUNT
 
1725
#if defined(DUK_OPT_NO_ARRAY_SPLICE_NONSTD_DELCOUNT)
 
1726
#undef DUK_USE_ARRAY_SPLICE_NONSTD_DELCOUNT
 
1727
#endif
 
1728
 
 
1729
/* Non-standard 'caller' property for function instances, see
 
1730
 * test-bi-function-nonstd-caller-prop.js.
 
1731
 */
 
1732
#undef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
1733
#if defined(DUK_OPT_FUNC_NONSTD_CALLER_PROPERTY)
 
1734
#define DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
1735
#endif
 
1736
 
 
1737
#define DUK_USE_PC2LINE
 
1738
#if defined(DUK_OPT_NO_PC2LINE)
 
1739
#undef DUK_USE_PC2LINE
 
1740
#endif
 
1741
 
 
1742
#undef DUK_USE_FUNC_NONSTD_SOURCE_PROPERTY
 
1743
#if defined(DUK_OPT_FUNC_NONSTD_SOURCE_PROPERTY)
 
1744
#define DUK_USE_FUNC_NONSTD_SOURCE_PROPERTY
 
1745
#endif
 
1746
 
 
1747
/*
 
1748
 *  Deep vs. shallow stack.
 
1749
 *
 
1750
 *  Some embedded platforms have very shallow stack (e.g. 64kB); default to
 
1751
 *  a shallow stack on unknown platforms or known embedded platforms.
 
1752
 */
 
1753
 
 
1754
#if defined(DUK_F_LINUX) || defined(DUK_F_BSD) || defined(DUK_F_WINDOWS) || \
 
1755
    defined(DUK_OPT_DEEP_C_STACK)
 
1756
#define DUK_USE_DEEP_C_STACK
 
1757
#else
 
1758
#undef DUK_USE_DEEP_C_STACK
 
1759
#endif
 
1760
 
 
1761
/*
 
1762
 *  User panic handler, panic exit behavior for default panic handler
 
1763
 */
 
1764
 
 
1765
#undef DUK_USE_PANIC_HANDLER
 
1766
#if defined(DUK_OPT_PANIC_HANDLER)
 
1767
#define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg))
 
1768
#endif
 
1769
 
 
1770
#undef DUK_USE_PANIC_ABORT
 
1771
#undef DUK_USE_PANIC_EXIT
 
1772
#undef DUK_USE_PANIC_SEGFAULT
 
1773
 
 
1774
#if defined(DUK_OPT_SEGFAULT_ON_PANIC)
 
1775
#define DUK_USE_PANIC_SEGFAULT
 
1776
#else
 
1777
#define DUK_USE_PANIC_ABORT
 
1778
#endif
 
1779
 
 
1780
/*
 
1781
 *  File I/O support.  This is now used in a few API calls to e.g. push
 
1782
 *  a string from file contents or eval a file.  For portability it must
 
1783
 *  be possible to disable I/O altogether.
 
1784
 */
 
1785
 
 
1786
#undef DUK_USE_FILE_IO
 
1787
#if !defined(DUK_OPT_NO_FILE_IO)
 
1788
#define DUK_USE_FILE_IO
 
1789
#endif
 
1790
 
 
1791
/*
 
1792
 *  Optional run-time self tests executed when a heap is created.  Some
 
1793
 *  platform/compiler issues cannot be determined at compile time.  One
 
1794
 *  particular example is the bug described in misc/clang_aliasing.c.
 
1795
 */
 
1796
 
 
1797
#undef DUK_USE_SELF_TESTS
 
1798
#if defined(DUK_OPT_SELF_TESTS)
 
1799
#define DUK_USE_SELF_TESTS
 
1800
#endif
 
1801
 
 
1802
/*
 
1803
 *  Codecs
 
1804
 */
 
1805
 
 
1806
#define DUK_USE_JSONX
 
1807
#if defined(DUK_OPT_NO_JSONX)
 
1808
#undef DUK_USE_JSONX
 
1809
#endif
 
1810
 
 
1811
#define DUK_USE_JSONC
 
1812
#if defined(DUK_OPT_NO_JSONC)
 
1813
#undef DUK_USE_JSONC
 
1814
#endif
 
1815
 
 
1816
/*
 
1817
 *  InitJS code
 
1818
 */
 
1819
 
 
1820
#define DUK_USE_INITJS
 
1821
 
 
1822
/*
 
1823
 *  Miscellaneous
 
1824
 */
 
1825
 
 
1826
#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
 
1827
#undef DUK_USE_EXPLICIT_NULL_INIT
 
1828
 
 
1829
#if !defined(DUK_USE_PACKED_TVAL)
 
1830
#define DUK_USE_EXPLICIT_NULL_INIT
 
1831
#endif
 
1832
 
 
1833
#define DUK_USE_ZERO_BUFFER_DATA
 
1834
#if defined(DUK_OPT_NO_ZERO_BUFFER_DATA)
 
1835
#undef DUK_USE_ZERO_BUFFER_DATA
 
1836
#endif
 
1837
 
 
1838
#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__))
 
1839
#define DUK_USE_VARIADIC_MACROS
 
1840
#else
 
1841
#undef DUK_USE_VARIADIC_MACROS
 
1842
#endif
 
1843
 
 
1844
/*
 
1845
 *  Variable size array initialization.
 
1846
 *
 
1847
 *  Variable size array at the end of a structure is nonportable. 
 
1848
 *  There are three alternatives:
 
1849
 *
 
1850
 *    1) C99 (flexible array member): char buf[]
 
1851
 *    2) Compiler specific (e.g. GCC): char buf[0]
 
1852
 *    3) Portable but wastes memory / complicates allocation: char buf[1]
 
1853
 */
 
1854
 
 
1855
/* XXX: Currently unused, only hbuffer.h needed this at some point. */
 
1856
#undef DUK_USE_FLEX_C99
 
1857
#undef DUK_USE_FLEX_ZEROSIZE
 
1858
#undef DUK_USE_FLEX_ONESIZE
 
1859
#if defined(DUK_F_C99)
 
1860
#define DUK_USE_FLEX_C99
 
1861
#elif defined(__GNUC__)
 
1862
#define DUK_USE_FLEX_ZEROSIZE
 
1863
#else
 
1864
#define DUK_USE_FLEX_ONESIZE
 
1865
#endif
 
1866
 
 
1867
/*
 
1868
 *  GCC pragmas
 
1869
 */
 
1870
 
 
1871
/* XXX: GCC pragma inside a function fails in some earlier GCC versions (e.g. gcc 4.5).
 
1872
 * This is very approximate but allows clean builds for development right now.
 
1873
 */
 
1874
/* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html */
 
1875
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
 
1876
#define DUK_USE_GCC_PRAGMAS
 
1877
#else
 
1878
#undef DUK_USE_GCC_PRAGMAS
 
1879
#endif
 
1880
 
 
1881
/*
 
1882
 *  User declarations
 
1883
 */
 
1884
 
 
1885
#if defined(DUK_OPT_DECLARE)
 
1886
#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE
 
1887
#else
 
1888
#define DUK_USE_USER_DECLARE() /* no user declarations */
 
1889
#endif
 
1890
 
 
1891
/*
 
1892
 *  Alternative customization header
 
1893
 *
 
1894
 *  If you want to modify the final DUK_USE_xxx flags directly (without
 
1895
 *  using the available DUK_OPT_Xxx flags), define DUK_OPT_HAVE_CUSTOM_H
 
1896
 *  and tweak the final flags there.
 
1897
 */
 
1898
 
 
1899
#if defined(DUK_OPT_HAVE_CUSTOM_H)
 
1900
#include "duk_custom.h"
 
1901
#endif
 
1902
 
 
1903
#endif  /* DUK_FEATURES_H_INCLUDED */
 
1904
 
 
1905
#line 20 "duk_internal.h"
 
1906
#include "duktape.h"
 
1907
#line 1 "duk_features_sanity.h"
 
1908
/*
 
1909
 *  Sanity check of duk_features.h defines.  This is a separate file
 
1910
 *  because we also check for consistency between duktape.h and
 
1911
 *  duk_features.h defines.  Duktape.h cannot be included first
 
1912
 *  because feature selection macros would then be incorrect.
 
1913
 *  This file can also double check user tweaks made by an optional
 
1914
 *  duk_custom.h header.
 
1915
 */
 
1916
 
 
1917
#ifndef DUK_FEATURES_SANITY_H_INCLUDED
 
1918
#define DUK_FEATURES_SANITY_H_INCLUDED
 
1919
 
 
1920
#if defined(DUK_DDEBUG) && !defined(DUK_DEBUG)
 
1921
#error DUK_DEBUG and DUK_DDEBUG should not be defined (obsolete)
 
1922
#endif
 
1923
 
 
1924
#if defined(DUK_USE_DDEBUG) && !defined(DUK_USE_DEBUG)
 
1925
#error DUK_USE_DDEBUG defined without DUK_USE_DEBUG
 
1926
#endif
 
1927
 
 
1928
#if defined(DUK_USE_DDDEBUG) && !defined(DUK_USE_DEBUG)
 
1929
#error DUK_USE_DDDEBUG defined without DUK_USE_DEBUG
 
1930
#endif
 
1931
 
 
1932
#if defined(DUK_USE_DDDEBUG) && !defined(DUK_USE_DDEBUG)
 
1933
#error DUK_USE_DDDEBUG defined without DUK_USE_DDEBUG
 
1934
#endif
 
1935
 
 
1936
#if defined(DUK_USE_REFERENCE_COUNTING) && !defined(DUK_USE_DOUBLE_LINKED_HEAP)
 
1937
#error DUK_USE_REFERENCE_COUNTING defined without DUK_USE_DOUBLE_LINKED_HEAP
 
1938
#endif
 
1939
 
 
1940
#if defined(DUK_USE_GC_TORTURE) && !defined(DUK_USE_MARK_AND_SWEEP)
 
1941
#error DUK_USE_GC_TORTURE defined without DUK_USE_MARK_AND_SWEEP
 
1942
#endif
 
1943
 
 
1944
#if (defined(DUK_USE_VARIADIC_MACROS) && !defined(DUK_API_VARIADIC_MACROS)) || \
 
1945
    (!defined(DUK_USE_VARIADIC_MACROS) && defined(DUK_API_VARIADIC_MACROS))
 
1946
#error DUK_USE_VARIADIC_MACROS and DUK_API_VARIADIC_MACROS must agree
 
1947
#endif
 
1948
 
 
1949
#endif  /* DUK_FEATURES_SANITY_H_INCLUDED */
 
1950
#line 1 "duk_dblunion.h"
 
1951
/*
 
1952
 *  Union to access IEEE double memory representation, indexes for double
 
1953
 *  memory representation, and some macros for double manipulation.
 
1954
 *
 
1955
 *  Also used by packed duk_tval.  Use a union for bit manipulation to
 
1956
 *  minimize aliasing issues in practice.  The C99 standard does not
 
1957
 *  guarantee that this should work, but it's a very widely supported
 
1958
 *  practice for low level manipulation.
 
1959
 *
 
1960
 *  IEEE double format summary:
 
1961
 *
 
1962
 *    seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
 
1963
 *       A        B        C        D        E        F        G        H
 
1964
 *
 
1965
 *    s       sign bit
 
1966
 *    eee...  exponent field
 
1967
 *    fff...  fraction
 
1968
 *
 
1969
 *  See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
 
1970
 *
 
1971
 *  NaNs are represented as exponent 0x7ff and mantissa != 0.  The NaN is a
 
1972
 *  signaling NaN when the highest bit of the mantissa is zero, and a quiet
 
1973
 *  NaN when the highest bit is set.
 
1974
 *
 
1975
 *  At least three memory layouts are relevant here:
 
1976
 *
 
1977
 *    A B C D E F G H    Big endian (e.g. 68k)           DUK_USE_DOUBLE_BE
 
1978
 *    H G F E D C B A    Little endian (e.g. x86)        DUK_USE_DOUBLE_LE
 
1979
 *    D C B A H G F E    Mixed/cross endian (e.g. ARM)   DUK_USE_DOUBLE_ME
 
1980
 *
 
1981
 *  ARM is a special case: ARM double values are in mixed/cross endian
 
1982
 *  format while ARM duk_uint64_t values are in standard little endian
 
1983
 *  format (H G F E D C B A).  When a double is read as a duk_uint64_t
 
1984
 *  from memory, the register will contain the (logical) value
 
1985
 *  E F G H A B C D.  This requires some special handling below.
 
1986
 *
 
1987
 *  Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
 
1988
 *  the logical (big endian) order:
 
1989
 *
 
1990
 *  byte order      duk_uint8_t    duk_uint16_t     duk_uint32_t    
 
1991
 *    BE             01234567         0123               01
 
1992
 *    LE             76543210         3210               10
 
1993
 *    ME (ARM)       32107654         1032               01
 
1994
 *
 
1995
 *  Some processors may alter NaN values in a floating point load+store.
 
1996
 *  For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
 
1997
 *  quiet one.  This is catastrophic when NaN space is used in packed
 
1998
 *  duk_tval values.  See: misc/clang_aliasing.c.
 
1999
 */
 
2000
 
 
2001
#ifndef DUK_DBLUNION_H_INCLUDED
 
2002
#define DUK_DBLUNION_H_INCLUDED
 
2003
 
 
2004
/*
 
2005
 *  Union for accessing double parts, also serves as packed duk_tval
 
2006
 */
 
2007
 
 
2008
union duk_double_union {
 
2009
        double d;
 
2010
#ifdef DUK_USE_64BIT_OPS
 
2011
        duk_uint64_t ull[1];
 
2012
#endif
 
2013
        duk_uint32_t ui[2];
 
2014
        duk_uint16_t us[4];
 
2015
        duk_uint8_t uc[8];
 
2016
#ifdef DUK_USE_PACKED_TVAL_POSSIBLE
 
2017
        void *vp[2];  /* used by packed duk_tval, assumes sizeof(void *) == 4 */
 
2018
#endif
 
2019
};
 
2020
 
 
2021
typedef union duk_double_union duk_double_union;
 
2022
 
 
2023
/*
 
2024
 *  Indexes of various types with respect to big endian (logical) layout
 
2025
 */
 
2026
 
 
2027
#if defined(DUK_USE_DOUBLE_LE)
 
2028
#ifdef DUK_USE_64BIT_OPS
 
2029
#define DUK_DBL_IDX_ULL0   0
 
2030
#endif
 
2031
#define DUK_DBL_IDX_UI0    1
 
2032
#define DUK_DBL_IDX_UI1    0
 
2033
#define DUK_DBL_IDX_US0    3
 
2034
#define DUK_DBL_IDX_US1    2
 
2035
#define DUK_DBL_IDX_US2    1
 
2036
#define DUK_DBL_IDX_US3    0
 
2037
#define DUK_DBL_IDX_UC0    7
 
2038
#define DUK_DBL_IDX_UC1    6
 
2039
#define DUK_DBL_IDX_UC2    5
 
2040
#define DUK_DBL_IDX_UC3    4
 
2041
#define DUK_DBL_IDX_UC4    3
 
2042
#define DUK_DBL_IDX_UC5    2
 
2043
#define DUK_DBL_IDX_UC6    1
 
2044
#define DUK_DBL_IDX_UC7    0
 
2045
#define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
 
2046
#define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
 
2047
#elif defined(DUK_USE_DOUBLE_BE)
 
2048
#ifdef DUK_USE_64BIT_OPS
 
2049
#define DUK_DBL_IDX_ULL0   0
 
2050
#endif
 
2051
#define DUK_DBL_IDX_UI0    0
 
2052
#define DUK_DBL_IDX_UI1    1
 
2053
#define DUK_DBL_IDX_US0    0
 
2054
#define DUK_DBL_IDX_US1    1
 
2055
#define DUK_DBL_IDX_US2    2
 
2056
#define DUK_DBL_IDX_US3    3
 
2057
#define DUK_DBL_IDX_UC0    0
 
2058
#define DUK_DBL_IDX_UC1    1
 
2059
#define DUK_DBL_IDX_UC2    2
 
2060
#define DUK_DBL_IDX_UC3    3
 
2061
#define DUK_DBL_IDX_UC4    4
 
2062
#define DUK_DBL_IDX_UC5    5
 
2063
#define DUK_DBL_IDX_UC6    6
 
2064
#define DUK_DBL_IDX_UC7    7
 
2065
#define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
 
2066
#define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
 
2067
#elif defined(DUK_USE_DOUBLE_ME)
 
2068
#ifdef DUK_USE_64BIT_OPS
 
2069
#define DUK_DBL_IDX_ULL0   0  /* not directly applicable, byte order differs from a double */
 
2070
#endif
 
2071
#define DUK_DBL_IDX_UI0    0
 
2072
#define DUK_DBL_IDX_UI1    1
 
2073
#define DUK_DBL_IDX_US0    1
 
2074
#define DUK_DBL_IDX_US1    0
 
2075
#define DUK_DBL_IDX_US2    3
 
2076
#define DUK_DBL_IDX_US3    2
 
2077
#define DUK_DBL_IDX_UC0    3
 
2078
#define DUK_DBL_IDX_UC1    2
 
2079
#define DUK_DBL_IDX_UC2    1
 
2080
#define DUK_DBL_IDX_UC3    0
 
2081
#define DUK_DBL_IDX_UC4    7
 
2082
#define DUK_DBL_IDX_UC5    6
 
2083
#define DUK_DBL_IDX_UC6    5
 
2084
#define DUK_DBL_IDX_UC7    4
 
2085
#define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
 
2086
#define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
 
2087
#else
 
2088
#error internal error
 
2089
#endif
 
2090
 
 
2091
/*
 
2092
 *  Helper macros for reading/writing memory representation parts, used
 
2093
 *  by duk_numconv.c and duk_tval.h.
 
2094
 */
 
2095
 
 
2096
#define DUK_DBLUNION_SET_DOUBLE(u,v)  do {  \
 
2097
                (u)->d = (v); \
 
2098
        } while (0)
 
2099
 
 
2100
#define DUK_DBLUNION_SET_HIGH32(u,v)  do {  \
 
2101
                (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
 
2102
        } while (0)
 
2103
 
 
2104
#ifdef DUK_USE_64BIT_OPS
 
2105
#ifdef DUK_USE_DOUBLE_ME
 
2106
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
 
2107
                (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
 
2108
        } while (0)
 
2109
#else
 
2110
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
 
2111
                (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
 
2112
        } while (0)
 
2113
#endif
 
2114
#else  /* DUK_USE_64BIT_OPS */
 
2115
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
 
2116
                (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
 
2117
                (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
 
2118
        } while (0)
 
2119
#endif  /* DUK_USE_64BIT_OPS */
 
2120
 
 
2121
#define DUK_DBLUNION_SET_LOW32(u,v)  do {  \
 
2122
                (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
 
2123
        } while (0)
 
2124
 
 
2125
#define DUK_DBLUNION_GET_DOUBLE(u)  ((u)->d)
 
2126
#define DUK_DBLUNION_GET_HIGH32(u)  ((u)->ui[DUK_DBL_IDX_UI0])
 
2127
#define DUK_DBLUNION_GET_LOW32(u)   ((u)->ui[DUK_DBL_IDX_UI1])
 
2128
 
 
2129
/*
 
2130
 *  Double NaN manipulation macros related to NaN normalization needed when
 
2131
 *  using the packed duk_tval representation.  NaN normalization is necessary
 
2132
 *  to keep double values compatible with the duk_tval format.
 
2133
 *
 
2134
 *  When packed duk_tval is used, the NaN space is used to store pointers
 
2135
 *  and other tagged values in addition to NaNs.  Actual NaNs are normalized
 
2136
 *  to a specific format.  The macros below are used by the implementation
 
2137
 *  to check and normalize NaN values when they might be created.  The macros
 
2138
 *  are essentially NOPs when the non-packed duk_tval representation is used.
 
2139
 *
 
2140
 *  A FULL check is exact and checks all bits.  A NOTFULL check is used by
 
2141
 *  the packed duk_tval and works correctly for all NaNs except those that
 
2142
 *  begin with 0x7ff0.  Since the 'normalized NaN' values used with packed
 
2143
 *  duk_tval begin with 0x7ff8, the partial check is reliable when packed
 
2144
 *  duk_tval is used.
 
2145
 *
 
2146
 *  The ME variant below is specifically for ARM byte order, which has the
 
2147
 *  feature that while doubles have a mixed byte order (32107654), unsigned
 
2148
 *  long long values has a little endian byte order (76543210).  When writing
 
2149
 *  a logical double value through a ULL pointer, the 32-bit words need to be
 
2150
 *  swapped; hence the #ifdefs below for ULL writes with DUK_USE_DOUBLE_ME.
 
2151
 *  This is not full ARM support but suffices for some environments.
 
2152
 */
 
2153
 
 
2154
#ifdef DUK_USE_64BIT_OPS
 
2155
#ifdef DUK_USE_DOUBLE_ME
 
2156
#define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
 
2157
                (u)->ull[DUK_DBL_IDX_ULL0] = 0x000000007ff80000ULL; \
 
2158
        } while (0)
 
2159
#else
 
2160
#define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
 
2161
                (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \
 
2162
        } while (0)
 
2163
#endif
 
2164
#else  /* DUK_USE_64BIT_OPS */
 
2165
#define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
 
2166
                (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
 
2167
                (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
 
2168
        } while (0)
 
2169
#endif  /* DUK_USE_64BIT_OPS */
 
2170
 
 
2171
#define DUK__DBLUNION_SET_NAN_NOTFULL(u)  do { \
 
2172
                (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
 
2173
        } while (0)
 
2174
 
 
2175
#ifdef DUK_USE_64BIT_OPS
 
2176
#ifdef DUK_USE_DOUBLE_ME
 
2177
#define DUK__DBLUNION_IS_NAN_FULL(u) \
 
2178
        /* E == 0x7ff, F != 0 => NaN */ \
 
2179
        ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
 
2180
         ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0))
 
2181
#else
 
2182
#define DUK__DBLUNION_IS_NAN_FULL(u) \
 
2183
        /* E == 0x7ff, F != 0 => NaN */ \
 
2184
        ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
 
2185
         ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0))
 
2186
#endif
 
2187
#else  /* DUK_USE_64BIT_OPS */
 
2188
#define DUK__DBLUNION_IS_NAN_FULL(u) \
 
2189
        /* E == 0x7ff, F != 0 => NaN */ \
 
2190
        ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
 
2191
         (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
 
2192
          (u)->ui[DUK_DBL_IDX_UI1] != 0))
 
2193
#endif  /* DUK_USE_64BIT_OPS */
 
2194
 
 
2195
#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
 
2196
        /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
 
2197
        ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
 
2198
         (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
 
2199
 
 
2200
#ifdef DUK_USE_64BIT_OPS
 
2201
#ifdef DUK_USE_DOUBLE_ME
 
2202
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
 
2203
        ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL)
 
2204
#else
 
2205
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
 
2206
        ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL)
 
2207
#endif
 
2208
#else  /* DUK_USE_64BIT_OPS */
 
2209
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
 
2210
        (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
 
2211
         ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
 
2212
#endif  /* DUK_USE_64BIT_OPS */
 
2213
 
 
2214
#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
 
2215
        /* E == 0x7ff, F == 8 => normalized NaN */ \
 
2216
        ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
 
2217
 
 
2218
#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u)  do { \
 
2219
                if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
 
2220
                        DUK__DBLUNION_SET_NAN_FULL((u)); \
 
2221
                } \
 
2222
        } while (0)
 
2223
 
 
2224
#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u)  do { \
 
2225
                if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
 
2226
                        DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
 
2227
                } \
 
2228
        } while (0)
 
2229
 
 
2230
/* Concrete macros for NaN handling used by the implementation internals.
 
2231
 * Chosen so that they match the duk_tval representation: with a packed
 
2232
 * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
 
2233
 * these are essentially NOPs.
 
2234
 */
 
2235
 
 
2236
#if defined(DUK_USE_PACKED_TVAL)
 
2237
#if defined(DUK_USE_FULL_TVAL)
 
2238
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
 
2239
#define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))
 
2240
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
 
2241
#define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_FULL((d))
 
2242
#else
 
2243
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
 
2244
#define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_NOTFULL((u))
 
2245
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
 
2246
#define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_NOTFULL((d))
 
2247
#endif
 
2248
#define DUK_DBLUNION_IS_NORMALIZED(u) \
 
2249
        (!DUK_DBLUNION_IS_NAN((u)) ||  /* either not a NaN */ \
 
2250
         DUK_DBLUNION_IS_NORMALIZED_NAN((u)))  /* or is a normalized NaN */
 
2251
#else  /* DUK_USE_PACKED_TVAL */
 
2252
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  /* nop: no need to normalize */
 
2253
#define DUK_DBLUNION_IS_NAN(u)               (DUK_ISNAN((u)->d))
 
2254
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    (DUK_ISNAN((u)->d))
 
2255
#define DUK_DBLUNION_IS_NORMALIZED(u)        1  /* all doubles are considered normalized */
 
2256
#define DUK_DBLUNION_SET_NAN(u)  do { \
 
2257
                /* in non-packed representation we don't care about which NaN is used */ \
 
2258
                (u)->d = DUK_DOUBLE_NAN; \
 
2259
        } while (0)
 
2260
#endif  /* DUK_USE_PACKED_TVAL */
 
2261
 
 
2262
#endif  /* DUK_DBLUNION_H_INCLUDED */
 
2263
#line 23 "duk_internal.h"
 
2264
 
 
2265
/*
 
2266
 *  User declarations, e.g. prototypes for user functions used by Duktape
 
2267
 *  macros.  Concretely, if DUK_OPT_PANIC_HANDLER is used and the macro
 
2268
 *  value calls a user function, it needs to be declared for Duktape
 
2269
 *  compilation to avoid warnings.
 
2270
 */
 
2271
 
 
2272
DUK_USE_USER_DECLARE()
 
2273
 
 
2274
/*
 
2275
 *  Duktape includes (other than duk_features.h)
 
2276
 *
 
2277
 *  The header files expect to be included in an order which satisfies header
 
2278
 *  dependencies correctly (the headers themselves don't include any other
 
2279
 *  includes).  Forward declarations are used to break circular struct/typedef
 
2280
 *  dependencies.
 
2281
 */
 
2282
 
 
2283
#line 1 "duk_replacements.h"
 
2284
#ifndef DUK_REPLACEMENTS_H_INCLUDED
 
2285
#define DUK_REPLACEMENTS_H_INCLUDED
 
2286
 
 
2287
#ifdef DUK_USE_REPL_FPCLASSIFY
 
2288
int duk_repl_fpclassify(double x);
 
2289
#endif
 
2290
 
 
2291
#ifdef DUK_USE_REPL_SIGNBIT
 
2292
int duk_repl_signbit(double x);
 
2293
#endif
 
2294
 
 
2295
#ifdef DUK_USE_REPL_ISFINITE
 
2296
int duk_repl_isfinite(double x);
 
2297
#endif
 
2298
 
 
2299
#ifdef DUK_USE_REPL_ISNAN
 
2300
int duk_repl_isnan(double x);
 
2301
#endif
 
2302
 
 
2303
#ifdef DUK_USE_REPL_ISINF
 
2304
int duk_repl_isinf(double x);
 
2305
#endif
 
2306
 
 
2307
#endif  /* DUK_REPLACEMENTS_H_INCLUDED */
 
2308
#line 1 "duk_jmpbuf.h"
 
2309
/*
 
2310
 *  Wrapper for jmp_buf.
 
2311
 *
 
2312
 *  This is used because jmp_buf is an array type for backward compatibility.
 
2313
 *  Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
 
2314
 *  behave more intuitively.
 
2315
 *
 
2316
 *  http://en.wikipedia.org/wiki/Setjmp.h#Member_types
 
2317
 */
 
2318
 
 
2319
#ifndef DUK_JMPBUF_H_INCLUDED
 
2320
#define DUK_JMPBUF_H_INCLUDED
 
2321
 
 
2322
struct duk_jmpbuf {
 
2323
        jmp_buf jb;
 
2324
};
 
2325
 
 
2326
#endif  /* DUK_JMPBUF_H_INCLUDED */
 
2327
 
 
2328
#line 1 "duk_forwdecl.h"
 
2329
/*
 
2330
 *  Forward declarations for all Duktape structures.
 
2331
 */
 
2332
 
 
2333
#ifndef DUK_FORWDECL_H_INCLUDED
 
2334
#define DUK_FORWDECL_H_INCLUDED
 
2335
 
 
2336
/*
 
2337
 *  Forward declarations
 
2338
 */
 
2339
 
 
2340
struct duk_jmpbuf;
 
2341
 
 
2342
/* duk_tval intentionally skipped */
 
2343
struct duk_heaphdr;
 
2344
struct duk_heaphdr_string;
 
2345
struct duk_hstring;
 
2346
struct duk_hobject;
 
2347
struct duk_hcompiledfunction;
 
2348
struct duk_hnativefunction;
 
2349
struct duk_hthread;
 
2350
struct duk_hbuffer;
 
2351
struct duk_hbuffer_fixed;
 
2352
struct duk_hbuffer_dynamic;
 
2353
 
 
2354
struct duk_propaccessor;
 
2355
union duk_propvalue;
 
2356
struct duk_propdesc;
 
2357
 
 
2358
struct duk_heap;
 
2359
 
 
2360
struct duk_activation;
 
2361
struct duk_catcher;
 
2362
struct duk_strcache;
 
2363
struct duk_ljstate;
 
2364
 
 
2365
#ifdef DUK_USE_DEBUG
 
2366
struct duk_fixedbuffer;
 
2367
#endif
 
2368
 
 
2369
struct duk_bitdecoder_ctx;
 
2370
struct duk_bitencoder_ctx;
 
2371
 
 
2372
struct duk_token;
 
2373
struct duk_re_token;
 
2374
struct duk_lexer_point;
 
2375
struct duk_lexer_ctx;
 
2376
 
 
2377
struct duk_compiler_instr;
 
2378
struct duk_compiler_func;
 
2379
struct duk_compiler_ctx;
 
2380
 
 
2381
struct duk_re_matcher_ctx;
 
2382
struct duk_re_compiler_ctx;
 
2383
 
 
2384
typedef struct duk_jmpbuf duk_jmpbuf;
 
2385
 
 
2386
/* duk_tval intentionally skipped */
 
2387
typedef struct duk_heaphdr duk_heaphdr;
 
2388
typedef struct duk_heaphdr_string duk_heaphdr_string;
 
2389
typedef struct duk_hstring duk_hstring;
 
2390
typedef struct duk_hobject duk_hobject;
 
2391
typedef struct duk_hcompiledfunction duk_hcompiledfunction;
 
2392
typedef struct duk_hnativefunction duk_hnativefunction;
 
2393
typedef struct duk_hthread duk_hthread;
 
2394
typedef struct duk_hbuffer duk_hbuffer;
 
2395
typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
 
2396
typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
 
2397
 
 
2398
typedef struct duk_propaccessor duk_propaccessor;
 
2399
typedef union duk_propvalue duk_propvalue;
 
2400
typedef struct duk_propdesc duk_propdesc;
 
2401
 
 
2402
typedef struct duk_heap duk_heap;
 
2403
 
 
2404
typedef struct duk_activation duk_activation;
 
2405
typedef struct duk_catcher duk_catcher;
 
2406
typedef struct duk_strcache duk_strcache;
 
2407
typedef struct duk_ljstate duk_ljstate;
 
2408
 
 
2409
#ifdef DUK_USE_DEBUG
 
2410
typedef struct duk_fixedbuffer duk_fixedbuffer;
 
2411
#endif
 
2412
 
 
2413
typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
 
2414
typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
 
2415
 
 
2416
typedef struct duk_token duk_token;
 
2417
typedef struct duk_re_token duk_re_token;
 
2418
typedef struct duk_lexer_point duk_lexer_point;
 
2419
typedef struct duk_lexer_ctx duk_lexer_ctx;
 
2420
 
 
2421
typedef struct duk_compiler_instr duk_compiler_instr;
 
2422
typedef struct duk_compiler_func duk_compiler_func;
 
2423
typedef struct duk_compiler_ctx duk_compiler_ctx;
 
2424
 
 
2425
typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
 
2426
typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
 
2427
        
 
2428
#endif  /* DUK_FORWDECL_H_INCLUDED */
 
2429
 
 
2430
#line 1 "duk_builtins.h"
 
2431
/*
 
2432
 *  Automatically generated by genbuiltins.py, do not edit!
 
2433
 */
 
2434
 
 
2435
#ifndef DUK_BUILTINS_H_INCLUDED
 
2436
#define DUK_BUILTINS_H_INCLUDED
 
2437
 
 
2438
#if defined(DUK_USE_DOUBLE_LE)
 
2439
extern const duk_uint8_t duk_strings_data[];
 
2440
 
 
2441
#define DUK_STRDATA_DATA_LENGTH                                       1854
 
2442
#define DUK_STRDATA_MAX_STRLEN                                        24
 
2443
 
 
2444
#define DUK_STRIDX_UC_LOGGER                                          0                              /* 'Logger' */
 
2445
#define DUK_STRIDX_UC_THREAD                                          1                              /* 'Thread' */
 
2446
#define DUK_STRIDX_UC_POINTER                                         2                              /* 'Pointer' */
 
2447
#define DUK_STRIDX_UC_BUFFER                                          3                              /* 'Buffer' */
 
2448
#define DUK_STRIDX_DEC_ENV                                            4                              /* 'DecEnv' */
 
2449
#define DUK_STRIDX_OBJ_ENV                                            5                              /* 'ObjEnv' */
 
2450
#define DUK_STRIDX_EMPTY_STRING                                       6                              /* '' */
 
2451
#define DUK_STRIDX_GLOBAL                                             7                              /* 'global' */
 
2452
#define DUK_STRIDX_UC_ARGUMENTS                                       8                              /* 'Arguments' */
 
2453
#define DUK_STRIDX_JSON                                               9                              /* 'JSON' */
 
2454
#define DUK_STRIDX_MATH                                               10                             /* 'Math' */
 
2455
#define DUK_STRIDX_UC_ERROR                                           11                             /* 'Error' */
 
2456
#define DUK_STRIDX_REG_EXP                                            12                             /* 'RegExp' */
 
2457
#define DUK_STRIDX_DATE                                               13                             /* 'Date' */
 
2458
#define DUK_STRIDX_UC_NUMBER                                          14                             /* 'Number' */
 
2459
#define DUK_STRIDX_UC_BOOLEAN                                         15                             /* 'Boolean' */
 
2460
#define DUK_STRIDX_UC_STRING                                          16                             /* 'String' */
 
2461
#define DUK_STRIDX_ARRAY                                              17                             /* 'Array' */
 
2462
#define DUK_STRIDX_UC_FUNCTION                                        18                             /* 'Function' */
 
2463
#define DUK_STRIDX_UC_OBJECT                                          19                             /* 'Object' */
 
2464
#define DUK_STRIDX_JSON_EXT_FUNCTION2                                 20                             /* '{_func:true}' */
 
2465
#define DUK_STRIDX_JSON_EXT_FUNCTION1                                 21                             /* '{"_func":true}' */
 
2466
#define DUK_STRIDX_JSON_EXT_NEGINF                                    22                             /* '{"_ninf":true}' */
 
2467
#define DUK_STRIDX_JSON_EXT_POSINF                                    23                             /* '{"_inf":true}' */
 
2468
#define DUK_STRIDX_JSON_EXT_NAN                                       24                             /* '{"_nan":true}' */
 
2469
#define DUK_STRIDX_JSON_EXT_UNDEFINED                                 25                             /* '{"_undef":true}' */
 
2470
#define DUK_STRIDX_TO_LOG_STRING                                      26                             /* 'toLogString' */
 
2471
#define DUK_STRIDX_CLOG                                               27                             /* 'clog' */
 
2472
#define DUK_STRIDX_LC_L                                               28                             /* 'l' */
 
2473
#define DUK_STRIDX_LC_N                                               29                             /* 'n' */
 
2474
#define DUK_STRIDX_LC_FATAL                                           30                             /* 'fatal' */
 
2475
#define DUK_STRIDX_LC_ERROR                                           31                             /* 'error' */
 
2476
#define DUK_STRIDX_LC_WARN                                            32                             /* 'warn' */
 
2477
#define DUK_STRIDX_LC_DEBUG                                           33                             /* 'debug' */
 
2478
#define DUK_STRIDX_LC_TRACE                                           34                             /* 'trace' */
 
2479
#define DUK_STRIDX_RAW                                                35                             /* 'raw' */
 
2480
#define DUK_STRIDX_FMT                                                36                             /* 'fmt' */
 
2481
#define DUK_STRIDX_CURRENT                                            37                             /* 'current' */
 
2482
#define DUK_STRIDX_RESUME                                             38                             /* 'resume' */
 
2483
#define DUK_STRIDX_COMPACT                                            39                             /* 'compact' */
 
2484
#define DUK_STRIDX_JSONC                                              40                             /* 'jsonc' */
 
2485
#define DUK_STRIDX_JSONX                                              41                             /* 'jsonx' */
 
2486
#define DUK_STRIDX_BASE64                                             42                             /* 'base64' */
 
2487
#define DUK_STRIDX_HEX                                                43                             /* 'hex' */
 
2488
#define DUK_STRIDX_DEC                                                44                             /* 'dec' */
 
2489
#define DUK_STRIDX_ENC                                                45                             /* 'enc' */
 
2490
#define DUK_STRIDX_FIN                                                46                             /* 'fin' */
 
2491
#define DUK_STRIDX_GC                                                 47                             /* 'gc' */
 
2492
#define DUK_STRIDX_ACT                                                48                             /* 'act' */
 
2493
#define DUK_STRIDX_LINE                                               49                             /* 'line' */
 
2494
#define DUK_STRIDX_LC_INFO                                            50                             /* 'info' */
 
2495
#define DUK_STRIDX_VERSION                                            51                             /* 'version' */
 
2496
#define DUK_STRIDX_ENV                                                52                             /* 'env' */
 
2497
#define DUK_STRIDX_ERRTHROW                                           53                             /* 'errthrow' */
 
2498
#define DUK_STRIDX_ERRCREATE                                          54                             /* 'errcreate' */
 
2499
#define DUK_STRIDX_COMPILE                                            55                             /* 'compile' */
 
2500
#define DUK_STRIDX_INT_REGBASE                                        56                             /* '\x00regbase' */
 
2501
#define DUK_STRIDX_INT_THREAD                                         57                             /* '\x00thread' */
 
2502
#define DUK_STRIDX_INT_FINALIZER                                      58                             /* '\x00finalizer' */
 
2503
#define DUK_STRIDX_INT_CALLEE                                         59                             /* '\x00callee' */
 
2504
#define DUK_STRIDX_INT_MAP                                            60                             /* '\x00map' */
 
2505
#define DUK_STRIDX_INT_ARGS                                           61                             /* '\x00args' */
 
2506
#define DUK_STRIDX_INT_THIS                                           62                             /* '\x00this' */
 
2507
#define DUK_STRIDX_INT_PC2LINE                                        63                             /* '\x00pc2line' */
 
2508
#define DUK_STRIDX_INT_SOURCE                                         64                             /* '\x00source' */
 
2509
#define DUK_STRIDX_INT_VARENV                                         65                             /* '\x00varenv' */
 
2510
#define DUK_STRIDX_INT_LEXENV                                         66                             /* '\x00lexenv' */
 
2511
#define DUK_STRIDX_INT_VARMAP                                         67                             /* '\x00varmap' */
 
2512
#define DUK_STRIDX_INT_FORMALS                                        68                             /* '\x00formals' */
 
2513
#define DUK_STRIDX_INT_BYTECODE                                       69                             /* '\x00bytecode' */
 
2514
#define DUK_STRIDX_INT_NEXT                                           70                             /* '\x00next' */
 
2515
#define DUK_STRIDX_INT_TARGET                                         71                             /* '\x00target' */
 
2516
#define DUK_STRIDX_INT_VALUE                                          72                             /* '\x00value' */
 
2517
#define DUK_STRIDX_LC_POINTER                                         73                             /* 'pointer' */
 
2518
#define DUK_STRIDX_LC_BUFFER                                          74                             /* 'buffer' */
 
2519
#define DUK_STRIDX_TRACEDATA                                          75                             /* 'tracedata' */
 
2520
#define DUK_STRIDX_LINE_NUMBER                                        76                             /* 'lineNumber' */
 
2521
#define DUK_STRIDX_FILE_NAME                                          77                             /* 'fileName' */
 
2522
#define DUK_STRIDX_PC                                                 78                             /* 'pc' */
 
2523
#define DUK_STRIDX_STACK                                              79                             /* 'stack' */
 
2524
#define DUK_STRIDX_THROW_TYPE_ERROR                                   80                             /* 'ThrowTypeError' */
 
2525
#define DUK_STRIDX_DUKTAPE                                            81                             /* 'Duktape' */
 
2526
#define DUK_STRIDX_CALLEE                                             82                             /* 'callee' */
 
2527
#define DUK_STRIDX_INVALID_DATE                                       83                             /* 'Invalid Date' */
 
2528
#define DUK_STRIDX_BRACKETED_ELLIPSIS                                 84                             /* '[...]' */
 
2529
#define DUK_STRIDX_NEWLINE_TAB                                        85                             /* '\n\t' */
 
2530
#define DUK_STRIDX_SPACE                                              86                             /* ' ' */
 
2531
#define DUK_STRIDX_COMMA                                              87                             /* ',' */
 
2532
#define DUK_STRIDX_MINUS_ZERO                                         88                             /* '-0' */
 
2533
#define DUK_STRIDX_PLUS_ZERO                                          89                             /* '+0' */
 
2534
#define DUK_STRIDX_ZERO                                               90                             /* '0' */
 
2535
#define DUK_STRIDX_MINUS_INFINITY                                     91                             /* '-Infinity' */
 
2536
#define DUK_STRIDX_PLUS_INFINITY                                      92                             /* '+Infinity' */
 
2537
#define DUK_STRIDX_INFINITY                                           93                             /* 'Infinity' */
 
2538
#define DUK_STRIDX_LC_OBJECT                                          94                             /* 'object' */
 
2539
#define DUK_STRIDX_LC_STRING                                          95                             /* 'string' */
 
2540
#define DUK_STRIDX_LC_NUMBER                                          96                             /* 'number' */
 
2541
#define DUK_STRIDX_LC_BOOLEAN                                         97                             /* 'boolean' */
 
2542
#define DUK_STRIDX_UNDEFINED                                          98                             /* 'undefined' */
 
2543
#define DUK_STRIDX_STRINGIFY                                          99                             /* 'stringify' */
 
2544
#define DUK_STRIDX_TAN                                                100                            /* 'tan' */
 
2545
#define DUK_STRIDX_SQRT                                               101                            /* 'sqrt' */
 
2546
#define DUK_STRIDX_SIN                                                102                            /* 'sin' */
 
2547
#define DUK_STRIDX_ROUND                                              103                            /* 'round' */
 
2548
#define DUK_STRIDX_RANDOM                                             104                            /* 'random' */
 
2549
#define DUK_STRIDX_POW                                                105                            /* 'pow' */
 
2550
#define DUK_STRIDX_MIN                                                106                            /* 'min' */
 
2551
#define DUK_STRIDX_MAX                                                107                            /* 'max' */
 
2552
#define DUK_STRIDX_LOG                                                108                            /* 'log' */
 
2553
#define DUK_STRIDX_FLOOR                                              109                            /* 'floor' */
 
2554
#define DUK_STRIDX_EXP                                                110                            /* 'exp' */
 
2555
#define DUK_STRIDX_COS                                                111                            /* 'cos' */
 
2556
#define DUK_STRIDX_CEIL                                               112                            /* 'ceil' */
 
2557
#define DUK_STRIDX_ATAN2                                              113                            /* 'atan2' */
 
2558
#define DUK_STRIDX_ATAN                                               114                            /* 'atan' */
 
2559
#define DUK_STRIDX_ASIN                                               115                            /* 'asin' */
 
2560
#define DUK_STRIDX_ACOS                                               116                            /* 'acos' */
 
2561
#define DUK_STRIDX_ABS                                                117                            /* 'abs' */
 
2562
#define DUK_STRIDX_SQRT2                                              118                            /* 'SQRT2' */
 
2563
#define DUK_STRIDX_SQRT1_2                                            119                            /* 'SQRT1_2' */
 
2564
#define DUK_STRIDX_PI                                                 120                            /* 'PI' */
 
2565
#define DUK_STRIDX_LOG10E                                             121                            /* 'LOG10E' */
 
2566
#define DUK_STRIDX_LOG2E                                              122                            /* 'LOG2E' */
 
2567
#define DUK_STRIDX_LN2                                                123                            /* 'LN2' */
 
2568
#define DUK_STRIDX_LN10                                               124                            /* 'LN10' */
 
2569
#define DUK_STRIDX_E                                                  125                            /* 'E' */
 
2570
#define DUK_STRIDX_MESSAGE                                            126                            /* 'message' */
 
2571
#define DUK_STRIDX_NAME                                               127                            /* 'name' */
 
2572
#define DUK_STRIDX_INPUT                                              128                            /* 'input' */
 
2573
#define DUK_STRIDX_INDEX                                              129                            /* 'index' */
 
2574
#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP                               130                            /* '(?:)' */
 
2575
#define DUK_STRIDX_LAST_INDEX                                         131                            /* 'lastIndex' */
 
2576
#define DUK_STRIDX_MULTILINE                                          132                            /* 'multiline' */
 
2577
#define DUK_STRIDX_IGNORE_CASE                                        133                            /* 'ignoreCase' */
 
2578
#define DUK_STRIDX_SOURCE                                             134                            /* 'source' */
 
2579
#define DUK_STRIDX_TEST                                               135                            /* 'test' */
 
2580
#define DUK_STRIDX_EXEC                                               136                            /* 'exec' */
 
2581
#define DUK_STRIDX_TO_GMT_STRING                                      137                            /* 'toGMTString' */
 
2582
#define DUK_STRIDX_SET_YEAR                                           138                            /* 'setYear' */
 
2583
#define DUK_STRIDX_GET_YEAR                                           139                            /* 'getYear' */
 
2584
#define DUK_STRIDX_TO_JSON                                            140                            /* 'toJSON' */
 
2585
#define DUK_STRIDX_TO_ISO_STRING                                      141                            /* 'toISOString' */
 
2586
#define DUK_STRIDX_TO_UTC_STRING                                      142                            /* 'toUTCString' */
 
2587
#define DUK_STRIDX_SET_UTC_FULL_YEAR                                  143                            /* 'setUTCFullYear' */
 
2588
#define DUK_STRIDX_SET_FULL_YEAR                                      144                            /* 'setFullYear' */
 
2589
#define DUK_STRIDX_SET_UTC_MONTH                                      145                            /* 'setUTCMonth' */
 
2590
#define DUK_STRIDX_SET_MONTH                                          146                            /* 'setMonth' */
 
2591
#define DUK_STRIDX_SET_UTC_DATE                                       147                            /* 'setUTCDate' */
 
2592
#define DUK_STRIDX_SET_DATE                                           148                            /* 'setDate' */
 
2593
#define DUK_STRIDX_SET_UTC_HOURS                                      149                            /* 'setUTCHours' */
 
2594
#define DUK_STRIDX_SET_HOURS                                          150                            /* 'setHours' */
 
2595
#define DUK_STRIDX_SET_UTC_MINUTES                                    151                            /* 'setUTCMinutes' */
 
2596
#define DUK_STRIDX_SET_MINUTES                                        152                            /* 'setMinutes' */
 
2597
#define DUK_STRIDX_SET_UTC_SECONDS                                    153                            /* 'setUTCSeconds' */
 
2598
#define DUK_STRIDX_SET_SECONDS                                        154                            /* 'setSeconds' */
 
2599
#define DUK_STRIDX_SET_UTC_MILLISECONDS                               155                            /* 'setUTCMilliseconds' */
 
2600
#define DUK_STRIDX_SET_MILLISECONDS                                   156                            /* 'setMilliseconds' */
 
2601
#define DUK_STRIDX_SET_TIME                                           157                            /* 'setTime' */
 
2602
#define DUK_STRIDX_GET_TIMEZONE_OFFSET                                158                            /* 'getTimezoneOffset' */
 
2603
#define DUK_STRIDX_GET_UTC_MILLISECONDS                               159                            /* 'getUTCMilliseconds' */
 
2604
#define DUK_STRIDX_GET_MILLISECONDS                                   160                            /* 'getMilliseconds' */
 
2605
#define DUK_STRIDX_GET_UTC_SECONDS                                    161                            /* 'getUTCSeconds' */
 
2606
#define DUK_STRIDX_GET_SECONDS                                        162                            /* 'getSeconds' */
 
2607
#define DUK_STRIDX_GET_UTC_MINUTES                                    163                            /* 'getUTCMinutes' */
 
2608
#define DUK_STRIDX_GET_MINUTES                                        164                            /* 'getMinutes' */
 
2609
#define DUK_STRIDX_GET_UTC_HOURS                                      165                            /* 'getUTCHours' */
 
2610
#define DUK_STRIDX_GET_HOURS                                          166                            /* 'getHours' */
 
2611
#define DUK_STRIDX_GET_UTC_DAY                                        167                            /* 'getUTCDay' */
 
2612
#define DUK_STRIDX_GET_DAY                                            168                            /* 'getDay' */
 
2613
#define DUK_STRIDX_GET_UTC_DATE                                       169                            /* 'getUTCDate' */
 
2614
#define DUK_STRIDX_GET_DATE                                           170                            /* 'getDate' */
 
2615
#define DUK_STRIDX_GET_UTC_MONTH                                      171                            /* 'getUTCMonth' */
 
2616
#define DUK_STRIDX_GET_MONTH                                          172                            /* 'getMonth' */
 
2617
#define DUK_STRIDX_GET_UTC_FULL_YEAR                                  173                            /* 'getUTCFullYear' */
 
2618
#define DUK_STRIDX_GET_FULL_YEAR                                      174                            /* 'getFullYear' */
 
2619
#define DUK_STRIDX_GET_TIME                                           175                            /* 'getTime' */
 
2620
#define DUK_STRIDX_TO_LOCALE_TIME_STRING                              176                            /* 'toLocaleTimeString' */
 
2621
#define DUK_STRIDX_TO_LOCALE_DATE_STRING                              177                            /* 'toLocaleDateString' */
 
2622
#define DUK_STRIDX_TO_TIME_STRING                                     178                            /* 'toTimeString' */
 
2623
#define DUK_STRIDX_TO_DATE_STRING                                     179                            /* 'toDateString' */
 
2624
#define DUK_STRIDX_NOW                                                180                            /* 'now' */
 
2625
#define DUK_STRIDX_UTC                                                181                            /* 'UTC' */
 
2626
#define DUK_STRIDX_PARSE                                              182                            /* 'parse' */
 
2627
#define DUK_STRIDX_TO_PRECISION                                       183                            /* 'toPrecision' */
 
2628
#define DUK_STRIDX_TO_EXPONENTIAL                                     184                            /* 'toExponential' */
 
2629
#define DUK_STRIDX_TO_FIXED                                           185                            /* 'toFixed' */
 
2630
#define DUK_STRIDX_POSITIVE_INFINITY                                  186                            /* 'POSITIVE_INFINITY' */
 
2631
#define DUK_STRIDX_NEGATIVE_INFINITY                                  187                            /* 'NEGATIVE_INFINITY' */
 
2632
#define DUK_STRIDX_NAN                                                188                            /* 'NaN' */
 
2633
#define DUK_STRIDX_MIN_VALUE                                          189                            /* 'MIN_VALUE' */
 
2634
#define DUK_STRIDX_MAX_VALUE                                          190                            /* 'MAX_VALUE' */
 
2635
#define DUK_STRIDX_SUBSTR                                             191                            /* 'substr' */
 
2636
#define DUK_STRIDX_TRIM                                               192                            /* 'trim' */
 
2637
#define DUK_STRIDX_TO_LOCALE_UPPER_CASE                               193                            /* 'toLocaleUpperCase' */
 
2638
#define DUK_STRIDX_TO_UPPER_CASE                                      194                            /* 'toUpperCase' */
 
2639
#define DUK_STRIDX_TO_LOCALE_LOWER_CASE                               195                            /* 'toLocaleLowerCase' */
 
2640
#define DUK_STRIDX_TO_LOWER_CASE                                      196                            /* 'toLowerCase' */
 
2641
#define DUK_STRIDX_SUBSTRING                                          197                            /* 'substring' */
 
2642
#define DUK_STRIDX_SPLIT                                              198                            /* 'split' */
 
2643
#define DUK_STRIDX_SEARCH                                             199                            /* 'search' */
 
2644
#define DUK_STRIDX_REPLACE                                            200                            /* 'replace' */
 
2645
#define DUK_STRIDX_MATCH                                              201                            /* 'match' */
 
2646
#define DUK_STRIDX_LOCALE_COMPARE                                     202                            /* 'localeCompare' */
 
2647
#define DUK_STRIDX_CHAR_CODE_AT                                       203                            /* 'charCodeAt' */
 
2648
#define DUK_STRIDX_CHAR_AT                                            204                            /* 'charAt' */
 
2649
#define DUK_STRIDX_FROM_CHAR_CODE                                     205                            /* 'fromCharCode' */
 
2650
#define DUK_STRIDX_REDUCE_RIGHT                                       206                            /* 'reduceRight' */
 
2651
#define DUK_STRIDX_REDUCE                                             207                            /* 'reduce' */
 
2652
#define DUK_STRIDX_FILTER                                             208                            /* 'filter' */
 
2653
#define DUK_STRIDX_MAP                                                209                            /* 'map' */
 
2654
#define DUK_STRIDX_FOR_EACH                                           210                            /* 'forEach' */
 
2655
#define DUK_STRIDX_SOME                                               211                            /* 'some' */
 
2656
#define DUK_STRIDX_EVERY                                              212                            /* 'every' */
 
2657
#define DUK_STRIDX_LAST_INDEX_OF                                      213                            /* 'lastIndexOf' */
 
2658
#define DUK_STRIDX_INDEX_OF                                           214                            /* 'indexOf' */
 
2659
#define DUK_STRIDX_UNSHIFT                                            215                            /* 'unshift' */
 
2660
#define DUK_STRIDX_SPLICE                                             216                            /* 'splice' */
 
2661
#define DUK_STRIDX_SORT                                               217                            /* 'sort' */
 
2662
#define DUK_STRIDX_SLICE                                              218                            /* 'slice' */
 
2663
#define DUK_STRIDX_SHIFT                                              219                            /* 'shift' */
 
2664
#define DUK_STRIDX_REVERSE                                            220                            /* 'reverse' */
 
2665
#define DUK_STRIDX_PUSH                                               221                            /* 'push' */
 
2666
#define DUK_STRIDX_POP                                                222                            /* 'pop' */
 
2667
#define DUK_STRIDX_JOIN                                               223                            /* 'join' */
 
2668
#define DUK_STRIDX_CONCAT                                             224                            /* 'concat' */
 
2669
#define DUK_STRIDX_IS_ARRAY                                           225                            /* 'isArray' */
 
2670
#define DUK_STRIDX_LC_ARGUMENTS                                       226                            /* 'arguments' */
 
2671
#define DUK_STRIDX_CALLER                                             227                            /* 'caller' */
 
2672
#define DUK_STRIDX_BIND                                               228                            /* 'bind' */
 
2673
#define DUK_STRIDX_CALL                                               229                            /* 'call' */
 
2674
#define DUK_STRIDX_APPLY                                              230                            /* 'apply' */
 
2675
#define DUK_STRIDX_PROPERTY_IS_ENUMERABLE                             231                            /* 'propertyIsEnumerable' */
 
2676
#define DUK_STRIDX_IS_PROTOTYPE_OF                                    232                            /* 'isPrototypeOf' */
 
2677
#define DUK_STRIDX_HAS_OWN_PROPERTY                                   233                            /* 'hasOwnProperty' */
 
2678
#define DUK_STRIDX_VALUE_OF                                           234                            /* 'valueOf' */
 
2679
#define DUK_STRIDX_TO_LOCALE_STRING                                   235                            /* 'toLocaleString' */
 
2680
#define DUK_STRIDX_TO_STRING                                          236                            /* 'toString' */
 
2681
#define DUK_STRIDX_CONSTRUCTOR                                        237                            /* 'constructor' */
 
2682
#define DUK_STRIDX_SET                                                238                            /* 'set' */
 
2683
#define DUK_STRIDX_GET                                                239                            /* 'get' */
 
2684
#define DUK_STRIDX_ENUMERABLE                                         240                            /* 'enumerable' */
 
2685
#define DUK_STRIDX_CONFIGURABLE                                       241                            /* 'configurable' */
 
2686
#define DUK_STRIDX_WRITABLE                                           242                            /* 'writable' */
 
2687
#define DUK_STRIDX_VALUE                                              243                            /* 'value' */
 
2688
#define DUK_STRIDX_KEYS                                               244                            /* 'keys' */
 
2689
#define DUK_STRIDX_IS_EXTENSIBLE                                      245                            /* 'isExtensible' */
 
2690
#define DUK_STRIDX_IS_FROZEN                                          246                            /* 'isFrozen' */
 
2691
#define DUK_STRIDX_IS_SEALED                                          247                            /* 'isSealed' */
 
2692
#define DUK_STRIDX_PREVENT_EXTENSIONS                                 248                            /* 'preventExtensions' */
 
2693
#define DUK_STRIDX_FREEZE                                             249                            /* 'freeze' */
 
2694
#define DUK_STRIDX_SEAL                                               250                            /* 'seal' */
 
2695
#define DUK_STRIDX_DEFINE_PROPERTIES                                  251                            /* 'defineProperties' */
 
2696
#define DUK_STRIDX_DEFINE_PROPERTY                                    252                            /* 'defineProperty' */
 
2697
#define DUK_STRIDX_CREATE                                             253                            /* 'create' */
 
2698
#define DUK_STRIDX_GET_OWN_PROPERTY_NAMES                             254                            /* 'getOwnPropertyNames' */
 
2699
#define DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR                        255                            /* 'getOwnPropertyDescriptor' */
 
2700
#define DUK_STRIDX_GET_PROTOTYPE_OF                                   256                            /* 'getPrototypeOf' */
 
2701
#define DUK_STRIDX_PROTOTYPE                                          257                            /* 'prototype' */
 
2702
#define DUK_STRIDX_LENGTH                                             258                            /* 'length' */
 
2703
#define DUK_STRIDX_ALERT                                              259                            /* 'alert' */
 
2704
#define DUK_STRIDX_PRINT                                              260                            /* 'print' */
 
2705
#define DUK_STRIDX_UNESCAPE                                           261                            /* 'unescape' */
 
2706
#define DUK_STRIDX_ESCAPE                                             262                            /* 'escape' */
 
2707
#define DUK_STRIDX_ENCODE_URI_COMPONENT                               263                            /* 'encodeURIComponent' */
 
2708
#define DUK_STRIDX_ENCODE_URI                                         264                            /* 'encodeURI' */
 
2709
#define DUK_STRIDX_DECODE_URI_COMPONENT                               265                            /* 'decodeURIComponent' */
 
2710
#define DUK_STRIDX_DECODE_URI                                         266                            /* 'decodeURI' */
 
2711
#define DUK_STRIDX_IS_FINITE                                          267                            /* 'isFinite' */
 
2712
#define DUK_STRIDX_IS_NAN                                             268                            /* 'isNaN' */
 
2713
#define DUK_STRIDX_PARSE_FLOAT                                        269                            /* 'parseFloat' */
 
2714
#define DUK_STRIDX_PARSE_INT                                          270                            /* 'parseInt' */
 
2715
#define DUK_STRIDX_EVAL                                               271                            /* 'eval' */
 
2716
#define DUK_STRIDX_URI_ERROR                                          272                            /* 'URIError' */
 
2717
#define DUK_STRIDX_TYPE_ERROR                                         273                            /* 'TypeError' */
 
2718
#define DUK_STRIDX_SYNTAX_ERROR                                       274                            /* 'SyntaxError' */
 
2719
#define DUK_STRIDX_REFERENCE_ERROR                                    275                            /* 'ReferenceError' */
 
2720
#define DUK_STRIDX_RANGE_ERROR                                        276                            /* 'RangeError' */
 
2721
#define DUK_STRIDX_EVAL_ERROR                                         277                            /* 'EvalError' */
 
2722
#define DUK_STRIDX_BREAK                                              278                            /* 'break' */
 
2723
#define DUK_STRIDX_CASE                                               279                            /* 'case' */
 
2724
#define DUK_STRIDX_CATCH                                              280                            /* 'catch' */
 
2725
#define DUK_STRIDX_CONTINUE                                           281                            /* 'continue' */
 
2726
#define DUK_STRIDX_DEBUGGER                                           282                            /* 'debugger' */
 
2727
#define DUK_STRIDX_DEFAULT                                            283                            /* 'default' */
 
2728
#define DUK_STRIDX_DELETE                                             284                            /* 'delete' */
 
2729
#define DUK_STRIDX_DO                                                 285                            /* 'do' */
 
2730
#define DUK_STRIDX_ELSE                                               286                            /* 'else' */
 
2731
#define DUK_STRIDX_FINALLY                                            287                            /* 'finally' */
 
2732
#define DUK_STRIDX_FOR                                                288                            /* 'for' */
 
2733
#define DUK_STRIDX_LC_FUNCTION                                        289                            /* 'function' */
 
2734
#define DUK_STRIDX_IF                                                 290                            /* 'if' */
 
2735
#define DUK_STRIDX_IN                                                 291                            /* 'in' */
 
2736
#define DUK_STRIDX_INSTANCEOF                                         292                            /* 'instanceof' */
 
2737
#define DUK_STRIDX_NEW                                                293                            /* 'new' */
 
2738
#define DUK_STRIDX_RETURN                                             294                            /* 'return' */
 
2739
#define DUK_STRIDX_SWITCH                                             295                            /* 'switch' */
 
2740
#define DUK_STRIDX_THIS                                               296                            /* 'this' */
 
2741
#define DUK_STRIDX_THROW                                              297                            /* 'throw' */
 
2742
#define DUK_STRIDX_TRY                                                298                            /* 'try' */
 
2743
#define DUK_STRIDX_TYPEOF                                             299                            /* 'typeof' */
 
2744
#define DUK_STRIDX_VAR                                                300                            /* 'var' */
 
2745
#define DUK_STRIDX_VOID                                               301                            /* 'void' */
 
2746
#define DUK_STRIDX_WHILE                                              302                            /* 'while' */
 
2747
#define DUK_STRIDX_WITH                                               303                            /* 'with' */
 
2748
#define DUK_STRIDX_CLASS                                              304                            /* 'class' */
 
2749
#define DUK_STRIDX_CONST                                              305                            /* 'const' */
 
2750
#define DUK_STRIDX_ENUM                                               306                            /* 'enum' */
 
2751
#define DUK_STRIDX_EXPORT                                             307                            /* 'export' */
 
2752
#define DUK_STRIDX_EXTENDS                                            308                            /* 'extends' */
 
2753
#define DUK_STRIDX_IMPORT                                             309                            /* 'import' */
 
2754
#define DUK_STRIDX_SUPER                                              310                            /* 'super' */
 
2755
#define DUK_STRIDX_NULL                                               311                            /* 'null' */
 
2756
#define DUK_STRIDX_TRUE                                               312                            /* 'true' */
 
2757
#define DUK_STRIDX_FALSE                                              313                            /* 'false' */
 
2758
#define DUK_STRIDX_IMPLEMENTS                                         314                            /* 'implements' */
 
2759
#define DUK_STRIDX_INTERFACE                                          315                            /* 'interface' */
 
2760
#define DUK_STRIDX_LET                                                316                            /* 'let' */
 
2761
#define DUK_STRIDX_PACKAGE                                            317                            /* 'package' */
 
2762
#define DUK_STRIDX_PRIVATE                                            318                            /* 'private' */
 
2763
#define DUK_STRIDX_PROTECTED                                          319                            /* 'protected' */
 
2764
#define DUK_STRIDX_PUBLIC                                             320                            /* 'public' */
 
2765
#define DUK_STRIDX_STATIC                                             321                            /* 'static' */
 
2766
#define DUK_STRIDX_YIELD                                              322                            /* 'yield' */
 
2767
 
 
2768
#define DUK_HEAP_STRING_UC_LOGGER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_LOGGER)
 
2769
#define DUK_HTHREAD_STRING_UC_LOGGER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_LOGGER)
 
2770
#define DUK_HEAP_STRING_UC_THREAD(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
 
2771
#define DUK_HTHREAD_STRING_UC_THREAD(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
 
2772
#define DUK_HEAP_STRING_UC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
 
2773
#define DUK_HTHREAD_STRING_UC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
 
2774
#define DUK_HEAP_STRING_UC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
 
2775
#define DUK_HTHREAD_STRING_UC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
 
2776
#define DUK_HEAP_STRING_DEC_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
 
2777
#define DUK_HTHREAD_STRING_DEC_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
 
2778
#define DUK_HEAP_STRING_OBJ_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
 
2779
#define DUK_HTHREAD_STRING_OBJ_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
 
2780
#define DUK_HEAP_STRING_EMPTY_STRING(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
 
2781
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
 
2782
#define DUK_HEAP_STRING_GLOBAL(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
 
2783
#define DUK_HTHREAD_STRING_GLOBAL(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
 
2784
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
 
2785
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
 
2786
#define DUK_HEAP_STRING_JSON(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
 
2787
#define DUK_HTHREAD_STRING_JSON(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
 
2788
#define DUK_HEAP_STRING_MATH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
 
2789
#define DUK_HTHREAD_STRING_MATH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
 
2790
#define DUK_HEAP_STRING_UC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
 
2791
#define DUK_HTHREAD_STRING_UC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
 
2792
#define DUK_HEAP_STRING_REG_EXP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
 
2793
#define DUK_HTHREAD_STRING_REG_EXP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
 
2794
#define DUK_HEAP_STRING_DATE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
 
2795
#define DUK_HTHREAD_STRING_DATE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
 
2796
#define DUK_HEAP_STRING_UC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
 
2797
#define DUK_HTHREAD_STRING_UC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
 
2798
#define DUK_HEAP_STRING_UC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
 
2799
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
 
2800
#define DUK_HEAP_STRING_UC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
 
2801
#define DUK_HTHREAD_STRING_UC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
 
2802
#define DUK_HEAP_STRING_ARRAY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
 
2803
#define DUK_HTHREAD_STRING_ARRAY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
 
2804
#define DUK_HEAP_STRING_UC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
 
2805
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
 
2806
#define DUK_HEAP_STRING_UC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
 
2807
#define DUK_HTHREAD_STRING_UC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
 
2808
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
2809
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
2810
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
2811
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
2812
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
 
2813
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
 
2814
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
 
2815
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
 
2816
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
 
2817
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
 
2818
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
2819
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
2820
#define DUK_HEAP_STRING_TO_LOG_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
 
2821
#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
 
2822
#define DUK_HEAP_STRING_CLOG(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
 
2823
#define DUK_HTHREAD_STRING_CLOG(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
 
2824
#define DUK_HEAP_STRING_LC_L(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
 
2825
#define DUK_HTHREAD_STRING_LC_L(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
 
2826
#define DUK_HEAP_STRING_LC_N(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
 
2827
#define DUK_HTHREAD_STRING_LC_N(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
 
2828
#define DUK_HEAP_STRING_LC_FATAL(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
 
2829
#define DUK_HTHREAD_STRING_LC_FATAL(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
 
2830
#define DUK_HEAP_STRING_LC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
 
2831
#define DUK_HTHREAD_STRING_LC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
 
2832
#define DUK_HEAP_STRING_LC_WARN(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
 
2833
#define DUK_HTHREAD_STRING_LC_WARN(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
 
2834
#define DUK_HEAP_STRING_LC_DEBUG(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
 
2835
#define DUK_HTHREAD_STRING_LC_DEBUG(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
 
2836
#define DUK_HEAP_STRING_LC_TRACE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
 
2837
#define DUK_HTHREAD_STRING_LC_TRACE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
 
2838
#define DUK_HEAP_STRING_RAW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
 
2839
#define DUK_HTHREAD_STRING_RAW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
 
2840
#define DUK_HEAP_STRING_FMT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
 
2841
#define DUK_HTHREAD_STRING_FMT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
 
2842
#define DUK_HEAP_STRING_CURRENT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CURRENT)
 
2843
#define DUK_HTHREAD_STRING_CURRENT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CURRENT)
 
2844
#define DUK_HEAP_STRING_RESUME(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
 
2845
#define DUK_HTHREAD_STRING_RESUME(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
 
2846
#define DUK_HEAP_STRING_COMPACT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPACT)
 
2847
#define DUK_HTHREAD_STRING_COMPACT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPACT)
 
2848
#define DUK_HEAP_STRING_JSONC(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONC)
 
2849
#define DUK_HTHREAD_STRING_JSONC(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONC)
 
2850
#define DUK_HEAP_STRING_JSONX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONX)
 
2851
#define DUK_HTHREAD_STRING_JSONX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONX)
 
2852
#define DUK_HEAP_STRING_BASE64(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
 
2853
#define DUK_HTHREAD_STRING_BASE64(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
 
2854
#define DUK_HEAP_STRING_HEX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
 
2855
#define DUK_HTHREAD_STRING_HEX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
 
2856
#define DUK_HEAP_STRING_DEC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC)
 
2857
#define DUK_HTHREAD_STRING_DEC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC)
 
2858
#define DUK_HEAP_STRING_ENC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENC)
 
2859
#define DUK_HTHREAD_STRING_ENC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENC)
 
2860
#define DUK_HEAP_STRING_FIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FIN)
 
2861
#define DUK_HTHREAD_STRING_FIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FIN)
 
2862
#define DUK_HEAP_STRING_GC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GC)
 
2863
#define DUK_HTHREAD_STRING_GC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GC)
 
2864
#define DUK_HEAP_STRING_ACT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACT)
 
2865
#define DUK_HTHREAD_STRING_ACT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACT)
 
2866
#define DUK_HEAP_STRING_LINE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE)
 
2867
#define DUK_HTHREAD_STRING_LINE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE)
 
2868
#define DUK_HEAP_STRING_LC_INFO(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
 
2869
#define DUK_HTHREAD_STRING_LC_INFO(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
 
2870
#define DUK_HEAP_STRING_VERSION(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VERSION)
 
2871
#define DUK_HTHREAD_STRING_VERSION(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VERSION)
 
2872
#define DUK_HEAP_STRING_ENV(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
 
2873
#define DUK_HTHREAD_STRING_ENV(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
 
2874
#define DUK_HEAP_STRING_ERRTHROW(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRTHROW)
 
2875
#define DUK_HTHREAD_STRING_ERRTHROW(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRTHROW)
 
2876
#define DUK_HEAP_STRING_ERRCREATE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRCREATE)
 
2877
#define DUK_HTHREAD_STRING_ERRCREATE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRCREATE)
 
2878
#define DUK_HEAP_STRING_COMPILE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
 
2879
#define DUK_HTHREAD_STRING_COMPILE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
 
2880
#define DUK_HEAP_STRING_INT_REGBASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
 
2881
#define DUK_HTHREAD_STRING_INT_REGBASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
 
2882
#define DUK_HEAP_STRING_INT_THREAD(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
 
2883
#define DUK_HTHREAD_STRING_INT_THREAD(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
 
2884
#define DUK_HEAP_STRING_INT_FINALIZER(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
 
2885
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
 
2886
#define DUK_HEAP_STRING_INT_CALLEE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
 
2887
#define DUK_HTHREAD_STRING_INT_CALLEE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
 
2888
#define DUK_HEAP_STRING_INT_MAP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
 
2889
#define DUK_HTHREAD_STRING_INT_MAP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
 
2890
#define DUK_HEAP_STRING_INT_ARGS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
 
2891
#define DUK_HTHREAD_STRING_INT_ARGS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
 
2892
#define DUK_HEAP_STRING_INT_THIS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
 
2893
#define DUK_HTHREAD_STRING_INT_THIS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
 
2894
#define DUK_HEAP_STRING_INT_PC2LINE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
 
2895
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
 
2896
#define DUK_HEAP_STRING_INT_SOURCE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
 
2897
#define DUK_HTHREAD_STRING_INT_SOURCE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
 
2898
#define DUK_HEAP_STRING_INT_VARENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
 
2899
#define DUK_HTHREAD_STRING_INT_VARENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
 
2900
#define DUK_HEAP_STRING_INT_LEXENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
 
2901
#define DUK_HTHREAD_STRING_INT_LEXENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
 
2902
#define DUK_HEAP_STRING_INT_VARMAP(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
 
2903
#define DUK_HTHREAD_STRING_INT_VARMAP(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
 
2904
#define DUK_HEAP_STRING_INT_FORMALS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
 
2905
#define DUK_HTHREAD_STRING_INT_FORMALS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
 
2906
#define DUK_HEAP_STRING_INT_BYTECODE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
 
2907
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
 
2908
#define DUK_HEAP_STRING_INT_NEXT(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
 
2909
#define DUK_HTHREAD_STRING_INT_NEXT(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
 
2910
#define DUK_HEAP_STRING_INT_TARGET(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
 
2911
#define DUK_HTHREAD_STRING_INT_TARGET(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
 
2912
#define DUK_HEAP_STRING_INT_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
 
2913
#define DUK_HTHREAD_STRING_INT_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
 
2914
#define DUK_HEAP_STRING_LC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
 
2915
#define DUK_HTHREAD_STRING_LC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
 
2916
#define DUK_HEAP_STRING_LC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
 
2917
#define DUK_HTHREAD_STRING_LC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
 
2918
#define DUK_HEAP_STRING_TRACEDATA(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRACEDATA)
 
2919
#define DUK_HTHREAD_STRING_TRACEDATA(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRACEDATA)
 
2920
#define DUK_HEAP_STRING_LINE_NUMBER(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
 
2921
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
 
2922
#define DUK_HEAP_STRING_FILE_NAME(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
 
2923
#define DUK_HTHREAD_STRING_FILE_NAME(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
 
2924
#define DUK_HEAP_STRING_PC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
 
2925
#define DUK_HTHREAD_STRING_PC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
 
2926
#define DUK_HEAP_STRING_STACK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
 
2927
#define DUK_HTHREAD_STRING_STACK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
 
2928
#define DUK_HEAP_STRING_THROW_TYPE_ERROR(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW_TYPE_ERROR)
 
2929
#define DUK_HTHREAD_STRING_THROW_TYPE_ERROR(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW_TYPE_ERROR)
 
2930
#define DUK_HEAP_STRING_DUKTAPE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DUKTAPE)
 
2931
#define DUK_HTHREAD_STRING_DUKTAPE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DUKTAPE)
 
2932
#define DUK_HEAP_STRING_CALLEE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
 
2933
#define DUK_HTHREAD_STRING_CALLEE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
 
2934
#define DUK_HEAP_STRING_INVALID_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
 
2935
#define DUK_HTHREAD_STRING_INVALID_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
 
2936
#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
2937
#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
2938
#define DUK_HEAP_STRING_NEWLINE_TAB(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_TAB)
 
2939
#define DUK_HTHREAD_STRING_NEWLINE_TAB(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_TAB)
 
2940
#define DUK_HEAP_STRING_SPACE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
 
2941
#define DUK_HTHREAD_STRING_SPACE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
 
2942
#define DUK_HEAP_STRING_COMMA(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
 
2943
#define DUK_HTHREAD_STRING_COMMA(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
 
2944
#define DUK_HEAP_STRING_MINUS_ZERO(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
 
2945
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
 
2946
#define DUK_HEAP_STRING_PLUS_ZERO(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_ZERO)
 
2947
#define DUK_HTHREAD_STRING_PLUS_ZERO(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_ZERO)
 
2948
#define DUK_HEAP_STRING_ZERO(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ZERO)
 
2949
#define DUK_HTHREAD_STRING_ZERO(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ZERO)
 
2950
#define DUK_HEAP_STRING_MINUS_INFINITY(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
 
2951
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
 
2952
#define DUK_HEAP_STRING_PLUS_INFINITY(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_INFINITY)
 
2953
#define DUK_HTHREAD_STRING_PLUS_INFINITY(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_INFINITY)
 
2954
#define DUK_HEAP_STRING_INFINITY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
 
2955
#define DUK_HTHREAD_STRING_INFINITY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
 
2956
#define DUK_HEAP_STRING_LC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
 
2957
#define DUK_HTHREAD_STRING_LC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
 
2958
#define DUK_HEAP_STRING_LC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
 
2959
#define DUK_HTHREAD_STRING_LC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
 
2960
#define DUK_HEAP_STRING_LC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
 
2961
#define DUK_HTHREAD_STRING_LC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
 
2962
#define DUK_HEAP_STRING_LC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
 
2963
#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
 
2964
#define DUK_HEAP_STRING_UNDEFINED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNDEFINED)
 
2965
#define DUK_HTHREAD_STRING_UNDEFINED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNDEFINED)
 
2966
#define DUK_HEAP_STRING_STRINGIFY(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STRINGIFY)
 
2967
#define DUK_HTHREAD_STRING_STRINGIFY(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STRINGIFY)
 
2968
#define DUK_HEAP_STRING_TAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TAN)
 
2969
#define DUK_HTHREAD_STRING_TAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TAN)
 
2970
#define DUK_HEAP_STRING_SQRT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT)
 
2971
#define DUK_HTHREAD_STRING_SQRT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT)
 
2972
#define DUK_HEAP_STRING_SIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SIN)
 
2973
#define DUK_HTHREAD_STRING_SIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SIN)
 
2974
#define DUK_HEAP_STRING_ROUND(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ROUND)
 
2975
#define DUK_HTHREAD_STRING_ROUND(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ROUND)
 
2976
#define DUK_HEAP_STRING_RANDOM(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANDOM)
 
2977
#define DUK_HTHREAD_STRING_RANDOM(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANDOM)
 
2978
#define DUK_HEAP_STRING_POW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POW)
 
2979
#define DUK_HTHREAD_STRING_POW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POW)
 
2980
#define DUK_HEAP_STRING_MIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN)
 
2981
#define DUK_HTHREAD_STRING_MIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN)
 
2982
#define DUK_HEAP_STRING_MAX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX)
 
2983
#define DUK_HTHREAD_STRING_MAX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX)
 
2984
#define DUK_HEAP_STRING_LOG(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG)
 
2985
#define DUK_HTHREAD_STRING_LOG(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG)
 
2986
#define DUK_HEAP_STRING_FLOOR(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOOR)
 
2987
#define DUK_HTHREAD_STRING_FLOOR(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOOR)
 
2988
#define DUK_HEAP_STRING_EXP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXP)
 
2989
#define DUK_HTHREAD_STRING_EXP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXP)
 
2990
#define DUK_HEAP_STRING_COS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COS)
 
2991
#define DUK_HTHREAD_STRING_COS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COS)
 
2992
#define DUK_HEAP_STRING_CEIL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CEIL)
 
2993
#define DUK_HTHREAD_STRING_CEIL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CEIL)
 
2994
#define DUK_HEAP_STRING_ATAN2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN2)
 
2995
#define DUK_HTHREAD_STRING_ATAN2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN2)
 
2996
#define DUK_HEAP_STRING_ATAN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN)
 
2997
#define DUK_HTHREAD_STRING_ATAN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN)
 
2998
#define DUK_HEAP_STRING_ASIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ASIN)
 
2999
#define DUK_HTHREAD_STRING_ASIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ASIN)
 
3000
#define DUK_HEAP_STRING_ACOS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACOS)
 
3001
#define DUK_HTHREAD_STRING_ACOS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACOS)
 
3002
#define DUK_HEAP_STRING_ABS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ABS)
 
3003
#define DUK_HTHREAD_STRING_ABS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ABS)
 
3004
#define DUK_HEAP_STRING_SQRT2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT2)
 
3005
#define DUK_HTHREAD_STRING_SQRT2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT2)
 
3006
#define DUK_HEAP_STRING_SQRT1_2(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT1_2)
 
3007
#define DUK_HTHREAD_STRING_SQRT1_2(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT1_2)
 
3008
#define DUK_HEAP_STRING_PI(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PI)
 
3009
#define DUK_HTHREAD_STRING_PI(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PI)
 
3010
#define DUK_HEAP_STRING_LOG10E(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG10E)
 
3011
#define DUK_HTHREAD_STRING_LOG10E(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG10E)
 
3012
#define DUK_HEAP_STRING_LOG2E(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG2E)
 
3013
#define DUK_HTHREAD_STRING_LOG2E(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG2E)
 
3014
#define DUK_HEAP_STRING_LN2(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN2)
 
3015
#define DUK_HTHREAD_STRING_LN2(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN2)
 
3016
#define DUK_HEAP_STRING_LN10(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN10)
 
3017
#define DUK_HTHREAD_STRING_LN10(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN10)
 
3018
#define DUK_HEAP_STRING_E(heap)                                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_E)
 
3019
#define DUK_HTHREAD_STRING_E(thr)                                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_E)
 
3020
#define DUK_HEAP_STRING_MESSAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
 
3021
#define DUK_HTHREAD_STRING_MESSAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
 
3022
#define DUK_HEAP_STRING_NAME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
 
3023
#define DUK_HTHREAD_STRING_NAME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
 
3024
#define DUK_HEAP_STRING_INPUT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
 
3025
#define DUK_HTHREAD_STRING_INPUT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
 
3026
#define DUK_HEAP_STRING_INDEX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
 
3027
#define DUK_HTHREAD_STRING_INDEX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
 
3028
#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
3029
#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
3030
#define DUK_HEAP_STRING_LAST_INDEX(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
 
3031
#define DUK_HTHREAD_STRING_LAST_INDEX(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
 
3032
#define DUK_HEAP_STRING_MULTILINE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
 
3033
#define DUK_HTHREAD_STRING_MULTILINE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
 
3034
#define DUK_HEAP_STRING_IGNORE_CASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
 
3035
#define DUK_HTHREAD_STRING_IGNORE_CASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
 
3036
#define DUK_HEAP_STRING_SOURCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
 
3037
#define DUK_HTHREAD_STRING_SOURCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
 
3038
#define DUK_HEAP_STRING_TEST(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TEST)
 
3039
#define DUK_HTHREAD_STRING_TEST(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TEST)
 
3040
#define DUK_HEAP_STRING_EXEC(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXEC)
 
3041
#define DUK_HTHREAD_STRING_EXEC(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXEC)
 
3042
#define DUK_HEAP_STRING_TO_GMT_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
 
3043
#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
 
3044
#define DUK_HEAP_STRING_SET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_YEAR)
 
3045
#define DUK_HTHREAD_STRING_SET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_YEAR)
 
3046
#define DUK_HEAP_STRING_GET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_YEAR)
 
3047
#define DUK_HTHREAD_STRING_GET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_YEAR)
 
3048
#define DUK_HEAP_STRING_TO_JSON(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
 
3049
#define DUK_HTHREAD_STRING_TO_JSON(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
 
3050
#define DUK_HEAP_STRING_TO_ISO_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
 
3051
#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
 
3052
#define DUK_HEAP_STRING_TO_UTC_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
 
3053
#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
 
3054
#define DUK_HEAP_STRING_SET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
3055
#define DUK_HTHREAD_STRING_SET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
3056
#define DUK_HEAP_STRING_SET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_FULL_YEAR)
 
3057
#define DUK_HTHREAD_STRING_SET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_FULL_YEAR)
 
3058
#define DUK_HEAP_STRING_SET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MONTH)
 
3059
#define DUK_HTHREAD_STRING_SET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MONTH)
 
3060
#define DUK_HEAP_STRING_SET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MONTH)
 
3061
#define DUK_HTHREAD_STRING_SET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MONTH)
 
3062
#define DUK_HEAP_STRING_SET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_DATE)
 
3063
#define DUK_HTHREAD_STRING_SET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_DATE)
 
3064
#define DUK_HEAP_STRING_SET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_DATE)
 
3065
#define DUK_HTHREAD_STRING_SET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_DATE)
 
3066
#define DUK_HEAP_STRING_SET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_HOURS)
 
3067
#define DUK_HTHREAD_STRING_SET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_HOURS)
 
3068
#define DUK_HEAP_STRING_SET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_HOURS)
 
3069
#define DUK_HTHREAD_STRING_SET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_HOURS)
 
3070
#define DUK_HEAP_STRING_SET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MINUTES)
 
3071
#define DUK_HTHREAD_STRING_SET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MINUTES)
 
3072
#define DUK_HEAP_STRING_SET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MINUTES)
 
3073
#define DUK_HTHREAD_STRING_SET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MINUTES)
 
3074
#define DUK_HEAP_STRING_SET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_SECONDS)
 
3075
#define DUK_HTHREAD_STRING_SET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_SECONDS)
 
3076
#define DUK_HEAP_STRING_SET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_SECONDS)
 
3077
#define DUK_HTHREAD_STRING_SET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_SECONDS)
 
3078
#define DUK_HEAP_STRING_SET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
3079
#define DUK_HTHREAD_STRING_SET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
3080
#define DUK_HEAP_STRING_SET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MILLISECONDS)
 
3081
#define DUK_HTHREAD_STRING_SET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MILLISECONDS)
 
3082
#define DUK_HEAP_STRING_SET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_TIME)
 
3083
#define DUK_HTHREAD_STRING_SET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_TIME)
 
3084
#define DUK_HEAP_STRING_GET_TIMEZONE_OFFSET(heap)                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
3085
#define DUK_HTHREAD_STRING_GET_TIMEZONE_OFFSET(thr)                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
3086
#define DUK_HEAP_STRING_GET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
3087
#define DUK_HTHREAD_STRING_GET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
3088
#define DUK_HEAP_STRING_GET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MILLISECONDS)
 
3089
#define DUK_HTHREAD_STRING_GET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MILLISECONDS)
 
3090
#define DUK_HEAP_STRING_GET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_SECONDS)
 
3091
#define DUK_HTHREAD_STRING_GET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_SECONDS)
 
3092
#define DUK_HEAP_STRING_GET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_SECONDS)
 
3093
#define DUK_HTHREAD_STRING_GET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_SECONDS)
 
3094
#define DUK_HEAP_STRING_GET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MINUTES)
 
3095
#define DUK_HTHREAD_STRING_GET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MINUTES)
 
3096
#define DUK_HEAP_STRING_GET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MINUTES)
 
3097
#define DUK_HTHREAD_STRING_GET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MINUTES)
 
3098
#define DUK_HEAP_STRING_GET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_HOURS)
 
3099
#define DUK_HTHREAD_STRING_GET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_HOURS)
 
3100
#define DUK_HEAP_STRING_GET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_HOURS)
 
3101
#define DUK_HTHREAD_STRING_GET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_HOURS)
 
3102
#define DUK_HEAP_STRING_GET_UTC_DAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DAY)
 
3103
#define DUK_HTHREAD_STRING_GET_UTC_DAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DAY)
 
3104
#define DUK_HEAP_STRING_GET_DAY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DAY)
 
3105
#define DUK_HTHREAD_STRING_GET_DAY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DAY)
 
3106
#define DUK_HEAP_STRING_GET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DATE)
 
3107
#define DUK_HTHREAD_STRING_GET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DATE)
 
3108
#define DUK_HEAP_STRING_GET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DATE)
 
3109
#define DUK_HTHREAD_STRING_GET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DATE)
 
3110
#define DUK_HEAP_STRING_GET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MONTH)
 
3111
#define DUK_HTHREAD_STRING_GET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MONTH)
 
3112
#define DUK_HEAP_STRING_GET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MONTH)
 
3113
#define DUK_HTHREAD_STRING_GET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MONTH)
 
3114
#define DUK_HEAP_STRING_GET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
3115
#define DUK_HTHREAD_STRING_GET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
3116
#define DUK_HEAP_STRING_GET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_FULL_YEAR)
 
3117
#define DUK_HTHREAD_STRING_GET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_FULL_YEAR)
 
3118
#define DUK_HEAP_STRING_GET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIME)
 
3119
#define DUK_HTHREAD_STRING_GET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIME)
 
3120
#define DUK_HEAP_STRING_TO_LOCALE_TIME_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
3121
#define DUK_HTHREAD_STRING_TO_LOCALE_TIME_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
3122
#define DUK_HEAP_STRING_TO_LOCALE_DATE_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
3123
#define DUK_HTHREAD_STRING_TO_LOCALE_DATE_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
3124
#define DUK_HEAP_STRING_TO_TIME_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_TIME_STRING)
 
3125
#define DUK_HTHREAD_STRING_TO_TIME_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_TIME_STRING)
 
3126
#define DUK_HEAP_STRING_TO_DATE_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_DATE_STRING)
 
3127
#define DUK_HTHREAD_STRING_TO_DATE_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_DATE_STRING)
 
3128
#define DUK_HEAP_STRING_NOW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NOW)
 
3129
#define DUK_HTHREAD_STRING_NOW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NOW)
 
3130
#define DUK_HEAP_STRING_UTC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UTC)
 
3131
#define DUK_HTHREAD_STRING_UTC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UTC)
 
3132
#define DUK_HEAP_STRING_PARSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE)
 
3133
#define DUK_HTHREAD_STRING_PARSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE)
 
3134
#define DUK_HEAP_STRING_TO_PRECISION(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_PRECISION)
 
3135
#define DUK_HTHREAD_STRING_TO_PRECISION(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_PRECISION)
 
3136
#define DUK_HEAP_STRING_TO_EXPONENTIAL(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_EXPONENTIAL)
 
3137
#define DUK_HTHREAD_STRING_TO_EXPONENTIAL(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_EXPONENTIAL)
 
3138
#define DUK_HEAP_STRING_TO_FIXED(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_FIXED)
 
3139
#define DUK_HTHREAD_STRING_TO_FIXED(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_FIXED)
 
3140
#define DUK_HEAP_STRING_POSITIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POSITIVE_INFINITY)
 
3141
#define DUK_HTHREAD_STRING_POSITIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POSITIVE_INFINITY)
 
3142
#define DUK_HEAP_STRING_NEGATIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEGATIVE_INFINITY)
 
3143
#define DUK_HTHREAD_STRING_NEGATIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEGATIVE_INFINITY)
 
3144
#define DUK_HEAP_STRING_NAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
 
3145
#define DUK_HTHREAD_STRING_NAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
 
3146
#define DUK_HEAP_STRING_MIN_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN_VALUE)
 
3147
#define DUK_HTHREAD_STRING_MIN_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN_VALUE)
 
3148
#define DUK_HEAP_STRING_MAX_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX_VALUE)
 
3149
#define DUK_HTHREAD_STRING_MAX_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX_VALUE)
 
3150
#define DUK_HEAP_STRING_SUBSTR(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTR)
 
3151
#define DUK_HTHREAD_STRING_SUBSTR(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTR)
 
3152
#define DUK_HEAP_STRING_TRIM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRIM)
 
3153
#define DUK_HTHREAD_STRING_TRIM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRIM)
 
3154
#define DUK_HEAP_STRING_TO_LOCALE_UPPER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
3155
#define DUK_HTHREAD_STRING_TO_LOCALE_UPPER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
3156
#define DUK_HEAP_STRING_TO_UPPER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UPPER_CASE)
 
3157
#define DUK_HTHREAD_STRING_TO_UPPER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UPPER_CASE)
 
3158
#define DUK_HEAP_STRING_TO_LOCALE_LOWER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
3159
#define DUK_HTHREAD_STRING_TO_LOCALE_LOWER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
3160
#define DUK_HEAP_STRING_TO_LOWER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOWER_CASE)
 
3161
#define DUK_HTHREAD_STRING_TO_LOWER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOWER_CASE)
 
3162
#define DUK_HEAP_STRING_SUBSTRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTRING)
 
3163
#define DUK_HTHREAD_STRING_SUBSTRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTRING)
 
3164
#define DUK_HEAP_STRING_SPLIT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLIT)
 
3165
#define DUK_HTHREAD_STRING_SPLIT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLIT)
 
3166
#define DUK_HEAP_STRING_SEARCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEARCH)
 
3167
#define DUK_HTHREAD_STRING_SEARCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEARCH)
 
3168
#define DUK_HEAP_STRING_REPLACE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REPLACE)
 
3169
#define DUK_HTHREAD_STRING_REPLACE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REPLACE)
 
3170
#define DUK_HEAP_STRING_MATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATCH)
 
3171
#define DUK_HTHREAD_STRING_MATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATCH)
 
3172
#define DUK_HEAP_STRING_LOCALE_COMPARE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOCALE_COMPARE)
 
3173
#define DUK_HTHREAD_STRING_LOCALE_COMPARE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOCALE_COMPARE)
 
3174
#define DUK_HEAP_STRING_CHAR_CODE_AT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_CODE_AT)
 
3175
#define DUK_HTHREAD_STRING_CHAR_CODE_AT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_CODE_AT)
 
3176
#define DUK_HEAP_STRING_CHAR_AT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_AT)
 
3177
#define DUK_HTHREAD_STRING_CHAR_AT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_AT)
 
3178
#define DUK_HEAP_STRING_FROM_CHAR_CODE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FROM_CHAR_CODE)
 
3179
#define DUK_HTHREAD_STRING_FROM_CHAR_CODE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FROM_CHAR_CODE)
 
3180
#define DUK_HEAP_STRING_REDUCE_RIGHT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE_RIGHT)
 
3181
#define DUK_HTHREAD_STRING_REDUCE_RIGHT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE_RIGHT)
 
3182
#define DUK_HEAP_STRING_REDUCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE)
 
3183
#define DUK_HTHREAD_STRING_REDUCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE)
 
3184
#define DUK_HEAP_STRING_FILTER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILTER)
 
3185
#define DUK_HTHREAD_STRING_FILTER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILTER)
 
3186
#define DUK_HEAP_STRING_MAP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAP)
 
3187
#define DUK_HTHREAD_STRING_MAP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAP)
 
3188
#define DUK_HEAP_STRING_FOR_EACH(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR_EACH)
 
3189
#define DUK_HTHREAD_STRING_FOR_EACH(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR_EACH)
 
3190
#define DUK_HEAP_STRING_SOME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOME)
 
3191
#define DUK_HTHREAD_STRING_SOME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOME)
 
3192
#define DUK_HEAP_STRING_EVERY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVERY)
 
3193
#define DUK_HTHREAD_STRING_EVERY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVERY)
 
3194
#define DUK_HEAP_STRING_LAST_INDEX_OF(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX_OF)
 
3195
#define DUK_HTHREAD_STRING_LAST_INDEX_OF(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX_OF)
 
3196
#define DUK_HEAP_STRING_INDEX_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX_OF)
 
3197
#define DUK_HTHREAD_STRING_INDEX_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX_OF)
 
3198
#define DUK_HEAP_STRING_UNSHIFT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNSHIFT)
 
3199
#define DUK_HTHREAD_STRING_UNSHIFT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNSHIFT)
 
3200
#define DUK_HEAP_STRING_SPLICE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLICE)
 
3201
#define DUK_HTHREAD_STRING_SPLICE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLICE)
 
3202
#define DUK_HEAP_STRING_SORT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SORT)
 
3203
#define DUK_HTHREAD_STRING_SORT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SORT)
 
3204
#define DUK_HEAP_STRING_SLICE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SLICE)
 
3205
#define DUK_HTHREAD_STRING_SLICE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SLICE)
 
3206
#define DUK_HEAP_STRING_SHIFT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SHIFT)
 
3207
#define DUK_HTHREAD_STRING_SHIFT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SHIFT)
 
3208
#define DUK_HEAP_STRING_REVERSE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REVERSE)
 
3209
#define DUK_HTHREAD_STRING_REVERSE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REVERSE)
 
3210
#define DUK_HEAP_STRING_PUSH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUSH)
 
3211
#define DUK_HTHREAD_STRING_PUSH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUSH)
 
3212
#define DUK_HEAP_STRING_POP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POP)
 
3213
#define DUK_HTHREAD_STRING_POP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POP)
 
3214
#define DUK_HEAP_STRING_JOIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
 
3215
#define DUK_HTHREAD_STRING_JOIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
 
3216
#define DUK_HEAP_STRING_CONCAT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONCAT)
 
3217
#define DUK_HTHREAD_STRING_CONCAT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONCAT)
 
3218
#define DUK_HEAP_STRING_IS_ARRAY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_ARRAY)
 
3219
#define DUK_HTHREAD_STRING_IS_ARRAY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_ARRAY)
 
3220
#define DUK_HEAP_STRING_LC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
 
3221
#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
 
3222
#define DUK_HEAP_STRING_CALLER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
 
3223
#define DUK_HTHREAD_STRING_CALLER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
 
3224
#define DUK_HEAP_STRING_BIND(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BIND)
 
3225
#define DUK_HTHREAD_STRING_BIND(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BIND)
 
3226
#define DUK_HEAP_STRING_CALL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALL)
 
3227
#define DUK_HTHREAD_STRING_CALL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALL)
 
3228
#define DUK_HEAP_STRING_APPLY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
 
3229
#define DUK_HTHREAD_STRING_APPLY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
 
3230
#define DUK_HEAP_STRING_PROPERTY_IS_ENUMERABLE(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
3231
#define DUK_HTHREAD_STRING_PROPERTY_IS_ENUMERABLE(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
3232
#define DUK_HEAP_STRING_IS_PROTOTYPE_OF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_PROTOTYPE_OF)
 
3233
#define DUK_HTHREAD_STRING_IS_PROTOTYPE_OF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_PROTOTYPE_OF)
 
3234
#define DUK_HEAP_STRING_HAS_OWN_PROPERTY(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS_OWN_PROPERTY)
 
3235
#define DUK_HTHREAD_STRING_HAS_OWN_PROPERTY(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS_OWN_PROPERTY)
 
3236
#define DUK_HEAP_STRING_VALUE_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
 
3237
#define DUK_HTHREAD_STRING_VALUE_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
 
3238
#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
 
3239
#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
 
3240
#define DUK_HEAP_STRING_TO_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
 
3241
#define DUK_HTHREAD_STRING_TO_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
 
3242
#define DUK_HEAP_STRING_CONSTRUCTOR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
 
3243
#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
 
3244
#define DUK_HEAP_STRING_SET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
 
3245
#define DUK_HTHREAD_STRING_SET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
 
3246
#define DUK_HEAP_STRING_GET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
 
3247
#define DUK_HTHREAD_STRING_GET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
 
3248
#define DUK_HEAP_STRING_ENUMERABLE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
 
3249
#define DUK_HTHREAD_STRING_ENUMERABLE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
 
3250
#define DUK_HEAP_STRING_CONFIGURABLE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
 
3251
#define DUK_HTHREAD_STRING_CONFIGURABLE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
 
3252
#define DUK_HEAP_STRING_WRITABLE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
 
3253
#define DUK_HTHREAD_STRING_WRITABLE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
 
3254
#define DUK_HEAP_STRING_VALUE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
 
3255
#define DUK_HTHREAD_STRING_VALUE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
 
3256
#define DUK_HEAP_STRING_KEYS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_KEYS)
 
3257
#define DUK_HTHREAD_STRING_KEYS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_KEYS)
 
3258
#define DUK_HEAP_STRING_IS_EXTENSIBLE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_EXTENSIBLE)
 
3259
#define DUK_HTHREAD_STRING_IS_EXTENSIBLE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_EXTENSIBLE)
 
3260
#define DUK_HEAP_STRING_IS_FROZEN(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FROZEN)
 
3261
#define DUK_HTHREAD_STRING_IS_FROZEN(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FROZEN)
 
3262
#define DUK_HEAP_STRING_IS_SEALED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_SEALED)
 
3263
#define DUK_HTHREAD_STRING_IS_SEALED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_SEALED)
 
3264
#define DUK_HEAP_STRING_PREVENT_EXTENSIONS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PREVENT_EXTENSIONS)
 
3265
#define DUK_HTHREAD_STRING_PREVENT_EXTENSIONS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PREVENT_EXTENSIONS)
 
3266
#define DUK_HEAP_STRING_FREEZE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FREEZE)
 
3267
#define DUK_HTHREAD_STRING_FREEZE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FREEZE)
 
3268
#define DUK_HEAP_STRING_SEAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEAL)
 
3269
#define DUK_HTHREAD_STRING_SEAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEAL)
 
3270
#define DUK_HEAP_STRING_DEFINE_PROPERTIES(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTIES)
 
3271
#define DUK_HTHREAD_STRING_DEFINE_PROPERTIES(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTIES)
 
3272
#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
 
3273
#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
 
3274
#define DUK_HEAP_STRING_CREATE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CREATE)
 
3275
#define DUK_HTHREAD_STRING_CREATE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CREATE)
 
3276
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_NAMES(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
3277
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_NAMES(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
3278
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_DESCRIPTOR(heap)             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
3279
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_DESCRIPTOR(thr)           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
3280
#define DUK_HEAP_STRING_GET_PROTOTYPE_OF(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_PROTOTYPE_OF)
 
3281
#define DUK_HTHREAD_STRING_GET_PROTOTYPE_OF(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_PROTOTYPE_OF)
 
3282
#define DUK_HEAP_STRING_PROTOTYPE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
 
3283
#define DUK_HTHREAD_STRING_PROTOTYPE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
 
3284
#define DUK_HEAP_STRING_LENGTH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
 
3285
#define DUK_HTHREAD_STRING_LENGTH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
 
3286
#define DUK_HEAP_STRING_ALERT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ALERT)
 
3287
#define DUK_HTHREAD_STRING_ALERT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ALERT)
 
3288
#define DUK_HEAP_STRING_PRINT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRINT)
 
3289
#define DUK_HTHREAD_STRING_PRINT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRINT)
 
3290
#define DUK_HEAP_STRING_UNESCAPE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNESCAPE)
 
3291
#define DUK_HTHREAD_STRING_UNESCAPE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNESCAPE)
 
3292
#define DUK_HEAP_STRING_ESCAPE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPE)
 
3293
#define DUK_HTHREAD_STRING_ESCAPE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPE)
 
3294
#define DUK_HEAP_STRING_ENCODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
3295
#define DUK_HTHREAD_STRING_ENCODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
3296
#define DUK_HEAP_STRING_ENCODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI)
 
3297
#define DUK_HTHREAD_STRING_ENCODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI)
 
3298
#define DUK_HEAP_STRING_DECODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI_COMPONENT)
 
3299
#define DUK_HTHREAD_STRING_DECODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI_COMPONENT)
 
3300
#define DUK_HEAP_STRING_DECODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI)
 
3301
#define DUK_HTHREAD_STRING_DECODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI)
 
3302
#define DUK_HEAP_STRING_IS_FINITE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FINITE)
 
3303
#define DUK_HTHREAD_STRING_IS_FINITE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FINITE)
 
3304
#define DUK_HEAP_STRING_IS_NAN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_NAN)
 
3305
#define DUK_HTHREAD_STRING_IS_NAN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_NAN)
 
3306
#define DUK_HEAP_STRING_PARSE_FLOAT(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_FLOAT)
 
3307
#define DUK_HTHREAD_STRING_PARSE_FLOAT(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_FLOAT)
 
3308
#define DUK_HEAP_STRING_PARSE_INT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_INT)
 
3309
#define DUK_HTHREAD_STRING_PARSE_INT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_INT)
 
3310
#define DUK_HEAP_STRING_EVAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
 
3311
#define DUK_HTHREAD_STRING_EVAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
 
3312
#define DUK_HEAP_STRING_URI_ERROR(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_URI_ERROR)
 
3313
#define DUK_HTHREAD_STRING_URI_ERROR(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_URI_ERROR)
 
3314
#define DUK_HEAP_STRING_TYPE_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE_ERROR)
 
3315
#define DUK_HTHREAD_STRING_TYPE_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE_ERROR)
 
3316
#define DUK_HEAP_STRING_SYNTAX_ERROR(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SYNTAX_ERROR)
 
3317
#define DUK_HTHREAD_STRING_SYNTAX_ERROR(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SYNTAX_ERROR)
 
3318
#define DUK_HEAP_STRING_REFERENCE_ERROR(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REFERENCE_ERROR)
 
3319
#define DUK_HTHREAD_STRING_REFERENCE_ERROR(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REFERENCE_ERROR)
 
3320
#define DUK_HEAP_STRING_RANGE_ERROR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANGE_ERROR)
 
3321
#define DUK_HTHREAD_STRING_RANGE_ERROR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANGE_ERROR)
 
3322
#define DUK_HEAP_STRING_EVAL_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL_ERROR)
 
3323
#define DUK_HTHREAD_STRING_EVAL_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL_ERROR)
 
3324
#define DUK_HEAP_STRING_BREAK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
 
3325
#define DUK_HTHREAD_STRING_BREAK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
 
3326
#define DUK_HEAP_STRING_CASE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
 
3327
#define DUK_HTHREAD_STRING_CASE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
 
3328
#define DUK_HEAP_STRING_CATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
 
3329
#define DUK_HTHREAD_STRING_CATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
 
3330
#define DUK_HEAP_STRING_CONTINUE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
 
3331
#define DUK_HTHREAD_STRING_CONTINUE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
 
3332
#define DUK_HEAP_STRING_DEBUGGER(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
 
3333
#define DUK_HTHREAD_STRING_DEBUGGER(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
 
3334
#define DUK_HEAP_STRING_DEFAULT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
 
3335
#define DUK_HTHREAD_STRING_DEFAULT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
 
3336
#define DUK_HEAP_STRING_DELETE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
 
3337
#define DUK_HTHREAD_STRING_DELETE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
 
3338
#define DUK_HEAP_STRING_DO(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
 
3339
#define DUK_HTHREAD_STRING_DO(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
 
3340
#define DUK_HEAP_STRING_ELSE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
 
3341
#define DUK_HTHREAD_STRING_ELSE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
 
3342
#define DUK_HEAP_STRING_FINALLY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
 
3343
#define DUK_HTHREAD_STRING_FINALLY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
 
3344
#define DUK_HEAP_STRING_FOR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
 
3345
#define DUK_HTHREAD_STRING_FOR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
 
3346
#define DUK_HEAP_STRING_LC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
 
3347
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
 
3348
#define DUK_HEAP_STRING_IF(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
 
3349
#define DUK_HTHREAD_STRING_IF(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
 
3350
#define DUK_HEAP_STRING_IN(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
 
3351
#define DUK_HTHREAD_STRING_IN(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
 
3352
#define DUK_HEAP_STRING_INSTANCEOF(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
 
3353
#define DUK_HTHREAD_STRING_INSTANCEOF(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
 
3354
#define DUK_HEAP_STRING_NEW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
 
3355
#define DUK_HTHREAD_STRING_NEW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
 
3356
#define DUK_HEAP_STRING_RETURN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
 
3357
#define DUK_HTHREAD_STRING_RETURN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
 
3358
#define DUK_HEAP_STRING_SWITCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
 
3359
#define DUK_HTHREAD_STRING_SWITCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
 
3360
#define DUK_HEAP_STRING_THIS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
 
3361
#define DUK_HTHREAD_STRING_THIS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
 
3362
#define DUK_HEAP_STRING_THROW(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
 
3363
#define DUK_HTHREAD_STRING_THROW(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
 
3364
#define DUK_HEAP_STRING_TRY(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
 
3365
#define DUK_HTHREAD_STRING_TRY(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
 
3366
#define DUK_HEAP_STRING_TYPEOF(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
 
3367
#define DUK_HTHREAD_STRING_TYPEOF(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
 
3368
#define DUK_HEAP_STRING_VAR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
 
3369
#define DUK_HTHREAD_STRING_VAR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
 
3370
#define DUK_HEAP_STRING_VOID(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
 
3371
#define DUK_HTHREAD_STRING_VOID(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
 
3372
#define DUK_HEAP_STRING_WHILE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
 
3373
#define DUK_HTHREAD_STRING_WHILE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
 
3374
#define DUK_HEAP_STRING_WITH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
 
3375
#define DUK_HTHREAD_STRING_WITH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
 
3376
#define DUK_HEAP_STRING_CLASS(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
 
3377
#define DUK_HTHREAD_STRING_CLASS(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
 
3378
#define DUK_HEAP_STRING_CONST(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
 
3379
#define DUK_HTHREAD_STRING_CONST(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
 
3380
#define DUK_HEAP_STRING_ENUM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
 
3381
#define DUK_HTHREAD_STRING_ENUM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
 
3382
#define DUK_HEAP_STRING_EXPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
 
3383
#define DUK_HTHREAD_STRING_EXPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
 
3384
#define DUK_HEAP_STRING_EXTENDS(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
 
3385
#define DUK_HTHREAD_STRING_EXTENDS(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
 
3386
#define DUK_HEAP_STRING_IMPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
 
3387
#define DUK_HTHREAD_STRING_IMPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
 
3388
#define DUK_HEAP_STRING_SUPER(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
 
3389
#define DUK_HTHREAD_STRING_SUPER(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
 
3390
#define DUK_HEAP_STRING_NULL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NULL)
 
3391
#define DUK_HTHREAD_STRING_NULL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NULL)
 
3392
#define DUK_HEAP_STRING_TRUE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
 
3393
#define DUK_HTHREAD_STRING_TRUE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
 
3394
#define DUK_HEAP_STRING_FALSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
 
3395
#define DUK_HTHREAD_STRING_FALSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
 
3396
#define DUK_HEAP_STRING_IMPLEMENTS(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
 
3397
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
 
3398
#define DUK_HEAP_STRING_INTERFACE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
 
3399
#define DUK_HTHREAD_STRING_INTERFACE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
 
3400
#define DUK_HEAP_STRING_LET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
 
3401
#define DUK_HTHREAD_STRING_LET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
 
3402
#define DUK_HEAP_STRING_PACKAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
 
3403
#define DUK_HTHREAD_STRING_PACKAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
 
3404
#define DUK_HEAP_STRING_PRIVATE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
 
3405
#define DUK_HTHREAD_STRING_PRIVATE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
 
3406
#define DUK_HEAP_STRING_PROTECTED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
 
3407
#define DUK_HTHREAD_STRING_PROTECTED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
 
3408
#define DUK_HEAP_STRING_PUBLIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
 
3409
#define DUK_HTHREAD_STRING_PUBLIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
 
3410
#define DUK_HEAP_STRING_STATIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
 
3411
#define DUK_HTHREAD_STRING_STATIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
 
3412
#define DUK_HEAP_STRING_YIELD(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
 
3413
#define DUK_HTHREAD_STRING_YIELD(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
 
3414
 
 
3415
#define DUK_HEAP_NUM_STRINGS                                          323
 
3416
 
 
3417
#define DUK_STRIDX_START_RESERVED                                     278
 
3418
#define DUK_STRIDX_START_STRICT_RESERVED                              314
 
3419
#define DUK_STRIDX_END_RESERVED                                       323                            /* exclusive endpoint */
 
3420
 
 
3421
extern const duk_c_function duk_bi_native_functions[];
 
3422
extern const duk_uint8_t duk_builtins_data[];
 
3423
#ifdef DUK_USE_INITJS
 
3424
extern const duk_uint8_t duk_initjs_data[];
 
3425
#endif  /* DUK_USE_INITJS */
 
3426
 
 
3427
#define DUK_BUILTINS_DATA_LENGTH                                      1314
 
3428
#ifdef DUK_USE_INITJS
 
3429
#define DUK_INITJS_DATA_LENGTH                                        148
 
3430
#endif  /* DUK_USE_INITJS */
 
3431
 
 
3432
#define DUK_BIDX_GLOBAL                                               0
 
3433
#define DUK_BIDX_GLOBAL_ENV                                           1
 
3434
#define DUK_BIDX_OBJECT_CONSTRUCTOR                                   2
 
3435
#define DUK_BIDX_OBJECT_PROTOTYPE                                     3
 
3436
#define DUK_BIDX_FUNCTION_CONSTRUCTOR                                 4
 
3437
#define DUK_BIDX_FUNCTION_PROTOTYPE                                   5
 
3438
#define DUK_BIDX_ARRAY_CONSTRUCTOR                                    6
 
3439
#define DUK_BIDX_ARRAY_PROTOTYPE                                      7
 
3440
#define DUK_BIDX_STRING_CONSTRUCTOR                                   8
 
3441
#define DUK_BIDX_STRING_PROTOTYPE                                     9
 
3442
#define DUK_BIDX_BOOLEAN_CONSTRUCTOR                                  10
 
3443
#define DUK_BIDX_BOOLEAN_PROTOTYPE                                    11
 
3444
#define DUK_BIDX_NUMBER_CONSTRUCTOR                                   12
 
3445
#define DUK_BIDX_NUMBER_PROTOTYPE                                     13
 
3446
#define DUK_BIDX_DATE_CONSTRUCTOR                                     14
 
3447
#define DUK_BIDX_DATE_PROTOTYPE                                       15
 
3448
#define DUK_BIDX_REGEXP_CONSTRUCTOR                                   16
 
3449
#define DUK_BIDX_REGEXP_PROTOTYPE                                     17
 
3450
#define DUK_BIDX_ERROR_CONSTRUCTOR                                    18
 
3451
#define DUK_BIDX_ERROR_PROTOTYPE                                      19
 
3452
#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR                               20
 
3453
#define DUK_BIDX_EVAL_ERROR_PROTOTYPE                                 21
 
3454
#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR                              22
 
3455
#define DUK_BIDX_RANGE_ERROR_PROTOTYPE                                23
 
3456
#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR                          24
 
3457
#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE                            25
 
3458
#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR                             26
 
3459
#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE                               27
 
3460
#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR                               28
 
3461
#define DUK_BIDX_TYPE_ERROR_PROTOTYPE                                 29
 
3462
#define DUK_BIDX_URI_ERROR_CONSTRUCTOR                                30
 
3463
#define DUK_BIDX_URI_ERROR_PROTOTYPE                                  31
 
3464
#define DUK_BIDX_MATH                                                 32
 
3465
#define DUK_BIDX_JSON                                                 33
 
3466
#define DUK_BIDX_TYPE_ERROR_THROWER                                   34
 
3467
#define DUK_BIDX_DUKTAPE                                              35
 
3468
#define DUK_BIDX_THREAD_CONSTRUCTOR                                   36
 
3469
#define DUK_BIDX_THREAD_PROTOTYPE                                     37
 
3470
#define DUK_BIDX_BUFFER_CONSTRUCTOR                                   38
 
3471
#define DUK_BIDX_BUFFER_PROTOTYPE                                     39
 
3472
#define DUK_BIDX_POINTER_CONSTRUCTOR                                  40
 
3473
#define DUK_BIDX_POINTER_PROTOTYPE                                    41
 
3474
#define DUK_BIDX_LOGGER_CONSTRUCTOR                                   42
 
3475
#define DUK_BIDX_LOGGER_PROTOTYPE                                     43
 
3476
#define DUK_BIDX_DOUBLE_ERROR                                         44
 
3477
 
 
3478
#define DUK_NUM_BUILTINS                                              45
 
3479
 
 
3480
#elif defined(DUK_USE_DOUBLE_BE)
 
3481
extern const duk_uint8_t duk_strings_data[];
 
3482
 
 
3483
#define DUK_STRDATA_DATA_LENGTH                                       1854
 
3484
#define DUK_STRDATA_MAX_STRLEN                                        24
 
3485
 
 
3486
#define DUK_STRIDX_UC_LOGGER                                          0                              /* 'Logger' */
 
3487
#define DUK_STRIDX_UC_THREAD                                          1                              /* 'Thread' */
 
3488
#define DUK_STRIDX_UC_POINTER                                         2                              /* 'Pointer' */
 
3489
#define DUK_STRIDX_UC_BUFFER                                          3                              /* 'Buffer' */
 
3490
#define DUK_STRIDX_DEC_ENV                                            4                              /* 'DecEnv' */
 
3491
#define DUK_STRIDX_OBJ_ENV                                            5                              /* 'ObjEnv' */
 
3492
#define DUK_STRIDX_EMPTY_STRING                                       6                              /* '' */
 
3493
#define DUK_STRIDX_GLOBAL                                             7                              /* 'global' */
 
3494
#define DUK_STRIDX_UC_ARGUMENTS                                       8                              /* 'Arguments' */
 
3495
#define DUK_STRIDX_JSON                                               9                              /* 'JSON' */
 
3496
#define DUK_STRIDX_MATH                                               10                             /* 'Math' */
 
3497
#define DUK_STRIDX_UC_ERROR                                           11                             /* 'Error' */
 
3498
#define DUK_STRIDX_REG_EXP                                            12                             /* 'RegExp' */
 
3499
#define DUK_STRIDX_DATE                                               13                             /* 'Date' */
 
3500
#define DUK_STRIDX_UC_NUMBER                                          14                             /* 'Number' */
 
3501
#define DUK_STRIDX_UC_BOOLEAN                                         15                             /* 'Boolean' */
 
3502
#define DUK_STRIDX_UC_STRING                                          16                             /* 'String' */
 
3503
#define DUK_STRIDX_ARRAY                                              17                             /* 'Array' */
 
3504
#define DUK_STRIDX_UC_FUNCTION                                        18                             /* 'Function' */
 
3505
#define DUK_STRIDX_UC_OBJECT                                          19                             /* 'Object' */
 
3506
#define DUK_STRIDX_JSON_EXT_FUNCTION2                                 20                             /* '{_func:true}' */
 
3507
#define DUK_STRIDX_JSON_EXT_FUNCTION1                                 21                             /* '{"_func":true}' */
 
3508
#define DUK_STRIDX_JSON_EXT_NEGINF                                    22                             /* '{"_ninf":true}' */
 
3509
#define DUK_STRIDX_JSON_EXT_POSINF                                    23                             /* '{"_inf":true}' */
 
3510
#define DUK_STRIDX_JSON_EXT_NAN                                       24                             /* '{"_nan":true}' */
 
3511
#define DUK_STRIDX_JSON_EXT_UNDEFINED                                 25                             /* '{"_undef":true}' */
 
3512
#define DUK_STRIDX_TO_LOG_STRING                                      26                             /* 'toLogString' */
 
3513
#define DUK_STRIDX_CLOG                                               27                             /* 'clog' */
 
3514
#define DUK_STRIDX_LC_L                                               28                             /* 'l' */
 
3515
#define DUK_STRIDX_LC_N                                               29                             /* 'n' */
 
3516
#define DUK_STRIDX_LC_FATAL                                           30                             /* 'fatal' */
 
3517
#define DUK_STRIDX_LC_ERROR                                           31                             /* 'error' */
 
3518
#define DUK_STRIDX_LC_WARN                                            32                             /* 'warn' */
 
3519
#define DUK_STRIDX_LC_DEBUG                                           33                             /* 'debug' */
 
3520
#define DUK_STRIDX_LC_TRACE                                           34                             /* 'trace' */
 
3521
#define DUK_STRIDX_RAW                                                35                             /* 'raw' */
 
3522
#define DUK_STRIDX_FMT                                                36                             /* 'fmt' */
 
3523
#define DUK_STRIDX_CURRENT                                            37                             /* 'current' */
 
3524
#define DUK_STRIDX_RESUME                                             38                             /* 'resume' */
 
3525
#define DUK_STRIDX_COMPACT                                            39                             /* 'compact' */
 
3526
#define DUK_STRIDX_JSONC                                              40                             /* 'jsonc' */
 
3527
#define DUK_STRIDX_JSONX                                              41                             /* 'jsonx' */
 
3528
#define DUK_STRIDX_BASE64                                             42                             /* 'base64' */
 
3529
#define DUK_STRIDX_HEX                                                43                             /* 'hex' */
 
3530
#define DUK_STRIDX_DEC                                                44                             /* 'dec' */
 
3531
#define DUK_STRIDX_ENC                                                45                             /* 'enc' */
 
3532
#define DUK_STRIDX_FIN                                                46                             /* 'fin' */
 
3533
#define DUK_STRIDX_GC                                                 47                             /* 'gc' */
 
3534
#define DUK_STRIDX_ACT                                                48                             /* 'act' */
 
3535
#define DUK_STRIDX_LINE                                               49                             /* 'line' */
 
3536
#define DUK_STRIDX_LC_INFO                                            50                             /* 'info' */
 
3537
#define DUK_STRIDX_VERSION                                            51                             /* 'version' */
 
3538
#define DUK_STRIDX_ENV                                                52                             /* 'env' */
 
3539
#define DUK_STRIDX_ERRTHROW                                           53                             /* 'errthrow' */
 
3540
#define DUK_STRIDX_ERRCREATE                                          54                             /* 'errcreate' */
 
3541
#define DUK_STRIDX_COMPILE                                            55                             /* 'compile' */
 
3542
#define DUK_STRIDX_INT_REGBASE                                        56                             /* '\x00regbase' */
 
3543
#define DUK_STRIDX_INT_THREAD                                         57                             /* '\x00thread' */
 
3544
#define DUK_STRIDX_INT_FINALIZER                                      58                             /* '\x00finalizer' */
 
3545
#define DUK_STRIDX_INT_CALLEE                                         59                             /* '\x00callee' */
 
3546
#define DUK_STRIDX_INT_MAP                                            60                             /* '\x00map' */
 
3547
#define DUK_STRIDX_INT_ARGS                                           61                             /* '\x00args' */
 
3548
#define DUK_STRIDX_INT_THIS                                           62                             /* '\x00this' */
 
3549
#define DUK_STRIDX_INT_PC2LINE                                        63                             /* '\x00pc2line' */
 
3550
#define DUK_STRIDX_INT_SOURCE                                         64                             /* '\x00source' */
 
3551
#define DUK_STRIDX_INT_VARENV                                         65                             /* '\x00varenv' */
 
3552
#define DUK_STRIDX_INT_LEXENV                                         66                             /* '\x00lexenv' */
 
3553
#define DUK_STRIDX_INT_VARMAP                                         67                             /* '\x00varmap' */
 
3554
#define DUK_STRIDX_INT_FORMALS                                        68                             /* '\x00formals' */
 
3555
#define DUK_STRIDX_INT_BYTECODE                                       69                             /* '\x00bytecode' */
 
3556
#define DUK_STRIDX_INT_NEXT                                           70                             /* '\x00next' */
 
3557
#define DUK_STRIDX_INT_TARGET                                         71                             /* '\x00target' */
 
3558
#define DUK_STRIDX_INT_VALUE                                          72                             /* '\x00value' */
 
3559
#define DUK_STRIDX_LC_POINTER                                         73                             /* 'pointer' */
 
3560
#define DUK_STRIDX_LC_BUFFER                                          74                             /* 'buffer' */
 
3561
#define DUK_STRIDX_TRACEDATA                                          75                             /* 'tracedata' */
 
3562
#define DUK_STRIDX_LINE_NUMBER                                        76                             /* 'lineNumber' */
 
3563
#define DUK_STRIDX_FILE_NAME                                          77                             /* 'fileName' */
 
3564
#define DUK_STRIDX_PC                                                 78                             /* 'pc' */
 
3565
#define DUK_STRIDX_STACK                                              79                             /* 'stack' */
 
3566
#define DUK_STRIDX_THROW_TYPE_ERROR                                   80                             /* 'ThrowTypeError' */
 
3567
#define DUK_STRIDX_DUKTAPE                                            81                             /* 'Duktape' */
 
3568
#define DUK_STRIDX_CALLEE                                             82                             /* 'callee' */
 
3569
#define DUK_STRIDX_INVALID_DATE                                       83                             /* 'Invalid Date' */
 
3570
#define DUK_STRIDX_BRACKETED_ELLIPSIS                                 84                             /* '[...]' */
 
3571
#define DUK_STRIDX_NEWLINE_TAB                                        85                             /* '\n\t' */
 
3572
#define DUK_STRIDX_SPACE                                              86                             /* ' ' */
 
3573
#define DUK_STRIDX_COMMA                                              87                             /* ',' */
 
3574
#define DUK_STRIDX_MINUS_ZERO                                         88                             /* '-0' */
 
3575
#define DUK_STRIDX_PLUS_ZERO                                          89                             /* '+0' */
 
3576
#define DUK_STRIDX_ZERO                                               90                             /* '0' */
 
3577
#define DUK_STRIDX_MINUS_INFINITY                                     91                             /* '-Infinity' */
 
3578
#define DUK_STRIDX_PLUS_INFINITY                                      92                             /* '+Infinity' */
 
3579
#define DUK_STRIDX_INFINITY                                           93                             /* 'Infinity' */
 
3580
#define DUK_STRIDX_LC_OBJECT                                          94                             /* 'object' */
 
3581
#define DUK_STRIDX_LC_STRING                                          95                             /* 'string' */
 
3582
#define DUK_STRIDX_LC_NUMBER                                          96                             /* 'number' */
 
3583
#define DUK_STRIDX_LC_BOOLEAN                                         97                             /* 'boolean' */
 
3584
#define DUK_STRIDX_UNDEFINED                                          98                             /* 'undefined' */
 
3585
#define DUK_STRIDX_STRINGIFY                                          99                             /* 'stringify' */
 
3586
#define DUK_STRIDX_TAN                                                100                            /* 'tan' */
 
3587
#define DUK_STRIDX_SQRT                                               101                            /* 'sqrt' */
 
3588
#define DUK_STRIDX_SIN                                                102                            /* 'sin' */
 
3589
#define DUK_STRIDX_ROUND                                              103                            /* 'round' */
 
3590
#define DUK_STRIDX_RANDOM                                             104                            /* 'random' */
 
3591
#define DUK_STRIDX_POW                                                105                            /* 'pow' */
 
3592
#define DUK_STRIDX_MIN                                                106                            /* 'min' */
 
3593
#define DUK_STRIDX_MAX                                                107                            /* 'max' */
 
3594
#define DUK_STRIDX_LOG                                                108                            /* 'log' */
 
3595
#define DUK_STRIDX_FLOOR                                              109                            /* 'floor' */
 
3596
#define DUK_STRIDX_EXP                                                110                            /* 'exp' */
 
3597
#define DUK_STRIDX_COS                                                111                            /* 'cos' */
 
3598
#define DUK_STRIDX_CEIL                                               112                            /* 'ceil' */
 
3599
#define DUK_STRIDX_ATAN2                                              113                            /* 'atan2' */
 
3600
#define DUK_STRIDX_ATAN                                               114                            /* 'atan' */
 
3601
#define DUK_STRIDX_ASIN                                               115                            /* 'asin' */
 
3602
#define DUK_STRIDX_ACOS                                               116                            /* 'acos' */
 
3603
#define DUK_STRIDX_ABS                                                117                            /* 'abs' */
 
3604
#define DUK_STRIDX_SQRT2                                              118                            /* 'SQRT2' */
 
3605
#define DUK_STRIDX_SQRT1_2                                            119                            /* 'SQRT1_2' */
 
3606
#define DUK_STRIDX_PI                                                 120                            /* 'PI' */
 
3607
#define DUK_STRIDX_LOG10E                                             121                            /* 'LOG10E' */
 
3608
#define DUK_STRIDX_LOG2E                                              122                            /* 'LOG2E' */
 
3609
#define DUK_STRIDX_LN2                                                123                            /* 'LN2' */
 
3610
#define DUK_STRIDX_LN10                                               124                            /* 'LN10' */
 
3611
#define DUK_STRIDX_E                                                  125                            /* 'E' */
 
3612
#define DUK_STRIDX_MESSAGE                                            126                            /* 'message' */
 
3613
#define DUK_STRIDX_NAME                                               127                            /* 'name' */
 
3614
#define DUK_STRIDX_INPUT                                              128                            /* 'input' */
 
3615
#define DUK_STRIDX_INDEX                                              129                            /* 'index' */
 
3616
#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP                               130                            /* '(?:)' */
 
3617
#define DUK_STRIDX_LAST_INDEX                                         131                            /* 'lastIndex' */
 
3618
#define DUK_STRIDX_MULTILINE                                          132                            /* 'multiline' */
 
3619
#define DUK_STRIDX_IGNORE_CASE                                        133                            /* 'ignoreCase' */
 
3620
#define DUK_STRIDX_SOURCE                                             134                            /* 'source' */
 
3621
#define DUK_STRIDX_TEST                                               135                            /* 'test' */
 
3622
#define DUK_STRIDX_EXEC                                               136                            /* 'exec' */
 
3623
#define DUK_STRIDX_TO_GMT_STRING                                      137                            /* 'toGMTString' */
 
3624
#define DUK_STRIDX_SET_YEAR                                           138                            /* 'setYear' */
 
3625
#define DUK_STRIDX_GET_YEAR                                           139                            /* 'getYear' */
 
3626
#define DUK_STRIDX_TO_JSON                                            140                            /* 'toJSON' */
 
3627
#define DUK_STRIDX_TO_ISO_STRING                                      141                            /* 'toISOString' */
 
3628
#define DUK_STRIDX_TO_UTC_STRING                                      142                            /* 'toUTCString' */
 
3629
#define DUK_STRIDX_SET_UTC_FULL_YEAR                                  143                            /* 'setUTCFullYear' */
 
3630
#define DUK_STRIDX_SET_FULL_YEAR                                      144                            /* 'setFullYear' */
 
3631
#define DUK_STRIDX_SET_UTC_MONTH                                      145                            /* 'setUTCMonth' */
 
3632
#define DUK_STRIDX_SET_MONTH                                          146                            /* 'setMonth' */
 
3633
#define DUK_STRIDX_SET_UTC_DATE                                       147                            /* 'setUTCDate' */
 
3634
#define DUK_STRIDX_SET_DATE                                           148                            /* 'setDate' */
 
3635
#define DUK_STRIDX_SET_UTC_HOURS                                      149                            /* 'setUTCHours' */
 
3636
#define DUK_STRIDX_SET_HOURS                                          150                            /* 'setHours' */
 
3637
#define DUK_STRIDX_SET_UTC_MINUTES                                    151                            /* 'setUTCMinutes' */
 
3638
#define DUK_STRIDX_SET_MINUTES                                        152                            /* 'setMinutes' */
 
3639
#define DUK_STRIDX_SET_UTC_SECONDS                                    153                            /* 'setUTCSeconds' */
 
3640
#define DUK_STRIDX_SET_SECONDS                                        154                            /* 'setSeconds' */
 
3641
#define DUK_STRIDX_SET_UTC_MILLISECONDS                               155                            /* 'setUTCMilliseconds' */
 
3642
#define DUK_STRIDX_SET_MILLISECONDS                                   156                            /* 'setMilliseconds' */
 
3643
#define DUK_STRIDX_SET_TIME                                           157                            /* 'setTime' */
 
3644
#define DUK_STRIDX_GET_TIMEZONE_OFFSET                                158                            /* 'getTimezoneOffset' */
 
3645
#define DUK_STRIDX_GET_UTC_MILLISECONDS                               159                            /* 'getUTCMilliseconds' */
 
3646
#define DUK_STRIDX_GET_MILLISECONDS                                   160                            /* 'getMilliseconds' */
 
3647
#define DUK_STRIDX_GET_UTC_SECONDS                                    161                            /* 'getUTCSeconds' */
 
3648
#define DUK_STRIDX_GET_SECONDS                                        162                            /* 'getSeconds' */
 
3649
#define DUK_STRIDX_GET_UTC_MINUTES                                    163                            /* 'getUTCMinutes' */
 
3650
#define DUK_STRIDX_GET_MINUTES                                        164                            /* 'getMinutes' */
 
3651
#define DUK_STRIDX_GET_UTC_HOURS                                      165                            /* 'getUTCHours' */
 
3652
#define DUK_STRIDX_GET_HOURS                                          166                            /* 'getHours' */
 
3653
#define DUK_STRIDX_GET_UTC_DAY                                        167                            /* 'getUTCDay' */
 
3654
#define DUK_STRIDX_GET_DAY                                            168                            /* 'getDay' */
 
3655
#define DUK_STRIDX_GET_UTC_DATE                                       169                            /* 'getUTCDate' */
 
3656
#define DUK_STRIDX_GET_DATE                                           170                            /* 'getDate' */
 
3657
#define DUK_STRIDX_GET_UTC_MONTH                                      171                            /* 'getUTCMonth' */
 
3658
#define DUK_STRIDX_GET_MONTH                                          172                            /* 'getMonth' */
 
3659
#define DUK_STRIDX_GET_UTC_FULL_YEAR                                  173                            /* 'getUTCFullYear' */
 
3660
#define DUK_STRIDX_GET_FULL_YEAR                                      174                            /* 'getFullYear' */
 
3661
#define DUK_STRIDX_GET_TIME                                           175                            /* 'getTime' */
 
3662
#define DUK_STRIDX_TO_LOCALE_TIME_STRING                              176                            /* 'toLocaleTimeString' */
 
3663
#define DUK_STRIDX_TO_LOCALE_DATE_STRING                              177                            /* 'toLocaleDateString' */
 
3664
#define DUK_STRIDX_TO_TIME_STRING                                     178                            /* 'toTimeString' */
 
3665
#define DUK_STRIDX_TO_DATE_STRING                                     179                            /* 'toDateString' */
 
3666
#define DUK_STRIDX_NOW                                                180                            /* 'now' */
 
3667
#define DUK_STRIDX_UTC                                                181                            /* 'UTC' */
 
3668
#define DUK_STRIDX_PARSE                                              182                            /* 'parse' */
 
3669
#define DUK_STRIDX_TO_PRECISION                                       183                            /* 'toPrecision' */
 
3670
#define DUK_STRIDX_TO_EXPONENTIAL                                     184                            /* 'toExponential' */
 
3671
#define DUK_STRIDX_TO_FIXED                                           185                            /* 'toFixed' */
 
3672
#define DUK_STRIDX_POSITIVE_INFINITY                                  186                            /* 'POSITIVE_INFINITY' */
 
3673
#define DUK_STRIDX_NEGATIVE_INFINITY                                  187                            /* 'NEGATIVE_INFINITY' */
 
3674
#define DUK_STRIDX_NAN                                                188                            /* 'NaN' */
 
3675
#define DUK_STRIDX_MIN_VALUE                                          189                            /* 'MIN_VALUE' */
 
3676
#define DUK_STRIDX_MAX_VALUE                                          190                            /* 'MAX_VALUE' */
 
3677
#define DUK_STRIDX_SUBSTR                                             191                            /* 'substr' */
 
3678
#define DUK_STRIDX_TRIM                                               192                            /* 'trim' */
 
3679
#define DUK_STRIDX_TO_LOCALE_UPPER_CASE                               193                            /* 'toLocaleUpperCase' */
 
3680
#define DUK_STRIDX_TO_UPPER_CASE                                      194                            /* 'toUpperCase' */
 
3681
#define DUK_STRIDX_TO_LOCALE_LOWER_CASE                               195                            /* 'toLocaleLowerCase' */
 
3682
#define DUK_STRIDX_TO_LOWER_CASE                                      196                            /* 'toLowerCase' */
 
3683
#define DUK_STRIDX_SUBSTRING                                          197                            /* 'substring' */
 
3684
#define DUK_STRIDX_SPLIT                                              198                            /* 'split' */
 
3685
#define DUK_STRIDX_SEARCH                                             199                            /* 'search' */
 
3686
#define DUK_STRIDX_REPLACE                                            200                            /* 'replace' */
 
3687
#define DUK_STRIDX_MATCH                                              201                            /* 'match' */
 
3688
#define DUK_STRIDX_LOCALE_COMPARE                                     202                            /* 'localeCompare' */
 
3689
#define DUK_STRIDX_CHAR_CODE_AT                                       203                            /* 'charCodeAt' */
 
3690
#define DUK_STRIDX_CHAR_AT                                            204                            /* 'charAt' */
 
3691
#define DUK_STRIDX_FROM_CHAR_CODE                                     205                            /* 'fromCharCode' */
 
3692
#define DUK_STRIDX_REDUCE_RIGHT                                       206                            /* 'reduceRight' */
 
3693
#define DUK_STRIDX_REDUCE                                             207                            /* 'reduce' */
 
3694
#define DUK_STRIDX_FILTER                                             208                            /* 'filter' */
 
3695
#define DUK_STRIDX_MAP                                                209                            /* 'map' */
 
3696
#define DUK_STRIDX_FOR_EACH                                           210                            /* 'forEach' */
 
3697
#define DUK_STRIDX_SOME                                               211                            /* 'some' */
 
3698
#define DUK_STRIDX_EVERY                                              212                            /* 'every' */
 
3699
#define DUK_STRIDX_LAST_INDEX_OF                                      213                            /* 'lastIndexOf' */
 
3700
#define DUK_STRIDX_INDEX_OF                                           214                            /* 'indexOf' */
 
3701
#define DUK_STRIDX_UNSHIFT                                            215                            /* 'unshift' */
 
3702
#define DUK_STRIDX_SPLICE                                             216                            /* 'splice' */
 
3703
#define DUK_STRIDX_SORT                                               217                            /* 'sort' */
 
3704
#define DUK_STRIDX_SLICE                                              218                            /* 'slice' */
 
3705
#define DUK_STRIDX_SHIFT                                              219                            /* 'shift' */
 
3706
#define DUK_STRIDX_REVERSE                                            220                            /* 'reverse' */
 
3707
#define DUK_STRIDX_PUSH                                               221                            /* 'push' */
 
3708
#define DUK_STRIDX_POP                                                222                            /* 'pop' */
 
3709
#define DUK_STRIDX_JOIN                                               223                            /* 'join' */
 
3710
#define DUK_STRIDX_CONCAT                                             224                            /* 'concat' */
 
3711
#define DUK_STRIDX_IS_ARRAY                                           225                            /* 'isArray' */
 
3712
#define DUK_STRIDX_LC_ARGUMENTS                                       226                            /* 'arguments' */
 
3713
#define DUK_STRIDX_CALLER                                             227                            /* 'caller' */
 
3714
#define DUK_STRIDX_BIND                                               228                            /* 'bind' */
 
3715
#define DUK_STRIDX_CALL                                               229                            /* 'call' */
 
3716
#define DUK_STRIDX_APPLY                                              230                            /* 'apply' */
 
3717
#define DUK_STRIDX_PROPERTY_IS_ENUMERABLE                             231                            /* 'propertyIsEnumerable' */
 
3718
#define DUK_STRIDX_IS_PROTOTYPE_OF                                    232                            /* 'isPrototypeOf' */
 
3719
#define DUK_STRIDX_HAS_OWN_PROPERTY                                   233                            /* 'hasOwnProperty' */
 
3720
#define DUK_STRIDX_VALUE_OF                                           234                            /* 'valueOf' */
 
3721
#define DUK_STRIDX_TO_LOCALE_STRING                                   235                            /* 'toLocaleString' */
 
3722
#define DUK_STRIDX_TO_STRING                                          236                            /* 'toString' */
 
3723
#define DUK_STRIDX_CONSTRUCTOR                                        237                            /* 'constructor' */
 
3724
#define DUK_STRIDX_SET                                                238                            /* 'set' */
 
3725
#define DUK_STRIDX_GET                                                239                            /* 'get' */
 
3726
#define DUK_STRIDX_ENUMERABLE                                         240                            /* 'enumerable' */
 
3727
#define DUK_STRIDX_CONFIGURABLE                                       241                            /* 'configurable' */
 
3728
#define DUK_STRIDX_WRITABLE                                           242                            /* 'writable' */
 
3729
#define DUK_STRIDX_VALUE                                              243                            /* 'value' */
 
3730
#define DUK_STRIDX_KEYS                                               244                            /* 'keys' */
 
3731
#define DUK_STRIDX_IS_EXTENSIBLE                                      245                            /* 'isExtensible' */
 
3732
#define DUK_STRIDX_IS_FROZEN                                          246                            /* 'isFrozen' */
 
3733
#define DUK_STRIDX_IS_SEALED                                          247                            /* 'isSealed' */
 
3734
#define DUK_STRIDX_PREVENT_EXTENSIONS                                 248                            /* 'preventExtensions' */
 
3735
#define DUK_STRIDX_FREEZE                                             249                            /* 'freeze' */
 
3736
#define DUK_STRIDX_SEAL                                               250                            /* 'seal' */
 
3737
#define DUK_STRIDX_DEFINE_PROPERTIES                                  251                            /* 'defineProperties' */
 
3738
#define DUK_STRIDX_DEFINE_PROPERTY                                    252                            /* 'defineProperty' */
 
3739
#define DUK_STRIDX_CREATE                                             253                            /* 'create' */
 
3740
#define DUK_STRIDX_GET_OWN_PROPERTY_NAMES                             254                            /* 'getOwnPropertyNames' */
 
3741
#define DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR                        255                            /* 'getOwnPropertyDescriptor' */
 
3742
#define DUK_STRIDX_GET_PROTOTYPE_OF                                   256                            /* 'getPrototypeOf' */
 
3743
#define DUK_STRIDX_PROTOTYPE                                          257                            /* 'prototype' */
 
3744
#define DUK_STRIDX_LENGTH                                             258                            /* 'length' */
 
3745
#define DUK_STRIDX_ALERT                                              259                            /* 'alert' */
 
3746
#define DUK_STRIDX_PRINT                                              260                            /* 'print' */
 
3747
#define DUK_STRIDX_UNESCAPE                                           261                            /* 'unescape' */
 
3748
#define DUK_STRIDX_ESCAPE                                             262                            /* 'escape' */
 
3749
#define DUK_STRIDX_ENCODE_URI_COMPONENT                               263                            /* 'encodeURIComponent' */
 
3750
#define DUK_STRIDX_ENCODE_URI                                         264                            /* 'encodeURI' */
 
3751
#define DUK_STRIDX_DECODE_URI_COMPONENT                               265                            /* 'decodeURIComponent' */
 
3752
#define DUK_STRIDX_DECODE_URI                                         266                            /* 'decodeURI' */
 
3753
#define DUK_STRIDX_IS_FINITE                                          267                            /* 'isFinite' */
 
3754
#define DUK_STRIDX_IS_NAN                                             268                            /* 'isNaN' */
 
3755
#define DUK_STRIDX_PARSE_FLOAT                                        269                            /* 'parseFloat' */
 
3756
#define DUK_STRIDX_PARSE_INT                                          270                            /* 'parseInt' */
 
3757
#define DUK_STRIDX_EVAL                                               271                            /* 'eval' */
 
3758
#define DUK_STRIDX_URI_ERROR                                          272                            /* 'URIError' */
 
3759
#define DUK_STRIDX_TYPE_ERROR                                         273                            /* 'TypeError' */
 
3760
#define DUK_STRIDX_SYNTAX_ERROR                                       274                            /* 'SyntaxError' */
 
3761
#define DUK_STRIDX_REFERENCE_ERROR                                    275                            /* 'ReferenceError' */
 
3762
#define DUK_STRIDX_RANGE_ERROR                                        276                            /* 'RangeError' */
 
3763
#define DUK_STRIDX_EVAL_ERROR                                         277                            /* 'EvalError' */
 
3764
#define DUK_STRIDX_BREAK                                              278                            /* 'break' */
 
3765
#define DUK_STRIDX_CASE                                               279                            /* 'case' */
 
3766
#define DUK_STRIDX_CATCH                                              280                            /* 'catch' */
 
3767
#define DUK_STRIDX_CONTINUE                                           281                            /* 'continue' */
 
3768
#define DUK_STRIDX_DEBUGGER                                           282                            /* 'debugger' */
 
3769
#define DUK_STRIDX_DEFAULT                                            283                            /* 'default' */
 
3770
#define DUK_STRIDX_DELETE                                             284                            /* 'delete' */
 
3771
#define DUK_STRIDX_DO                                                 285                            /* 'do' */
 
3772
#define DUK_STRIDX_ELSE                                               286                            /* 'else' */
 
3773
#define DUK_STRIDX_FINALLY                                            287                            /* 'finally' */
 
3774
#define DUK_STRIDX_FOR                                                288                            /* 'for' */
 
3775
#define DUK_STRIDX_LC_FUNCTION                                        289                            /* 'function' */
 
3776
#define DUK_STRIDX_IF                                                 290                            /* 'if' */
 
3777
#define DUK_STRIDX_IN                                                 291                            /* 'in' */
 
3778
#define DUK_STRIDX_INSTANCEOF                                         292                            /* 'instanceof' */
 
3779
#define DUK_STRIDX_NEW                                                293                            /* 'new' */
 
3780
#define DUK_STRIDX_RETURN                                             294                            /* 'return' */
 
3781
#define DUK_STRIDX_SWITCH                                             295                            /* 'switch' */
 
3782
#define DUK_STRIDX_THIS                                               296                            /* 'this' */
 
3783
#define DUK_STRIDX_THROW                                              297                            /* 'throw' */
 
3784
#define DUK_STRIDX_TRY                                                298                            /* 'try' */
 
3785
#define DUK_STRIDX_TYPEOF                                             299                            /* 'typeof' */
 
3786
#define DUK_STRIDX_VAR                                                300                            /* 'var' */
 
3787
#define DUK_STRIDX_VOID                                               301                            /* 'void' */
 
3788
#define DUK_STRIDX_WHILE                                              302                            /* 'while' */
 
3789
#define DUK_STRIDX_WITH                                               303                            /* 'with' */
 
3790
#define DUK_STRIDX_CLASS                                              304                            /* 'class' */
 
3791
#define DUK_STRIDX_CONST                                              305                            /* 'const' */
 
3792
#define DUK_STRIDX_ENUM                                               306                            /* 'enum' */
 
3793
#define DUK_STRIDX_EXPORT                                             307                            /* 'export' */
 
3794
#define DUK_STRIDX_EXTENDS                                            308                            /* 'extends' */
 
3795
#define DUK_STRIDX_IMPORT                                             309                            /* 'import' */
 
3796
#define DUK_STRIDX_SUPER                                              310                            /* 'super' */
 
3797
#define DUK_STRIDX_NULL                                               311                            /* 'null' */
 
3798
#define DUK_STRIDX_TRUE                                               312                            /* 'true' */
 
3799
#define DUK_STRIDX_FALSE                                              313                            /* 'false' */
 
3800
#define DUK_STRIDX_IMPLEMENTS                                         314                            /* 'implements' */
 
3801
#define DUK_STRIDX_INTERFACE                                          315                            /* 'interface' */
 
3802
#define DUK_STRIDX_LET                                                316                            /* 'let' */
 
3803
#define DUK_STRIDX_PACKAGE                                            317                            /* 'package' */
 
3804
#define DUK_STRIDX_PRIVATE                                            318                            /* 'private' */
 
3805
#define DUK_STRIDX_PROTECTED                                          319                            /* 'protected' */
 
3806
#define DUK_STRIDX_PUBLIC                                             320                            /* 'public' */
 
3807
#define DUK_STRIDX_STATIC                                             321                            /* 'static' */
 
3808
#define DUK_STRIDX_YIELD                                              322                            /* 'yield' */
 
3809
 
 
3810
#define DUK_HEAP_STRING_UC_LOGGER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_LOGGER)
 
3811
#define DUK_HTHREAD_STRING_UC_LOGGER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_LOGGER)
 
3812
#define DUK_HEAP_STRING_UC_THREAD(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
 
3813
#define DUK_HTHREAD_STRING_UC_THREAD(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
 
3814
#define DUK_HEAP_STRING_UC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
 
3815
#define DUK_HTHREAD_STRING_UC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
 
3816
#define DUK_HEAP_STRING_UC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
 
3817
#define DUK_HTHREAD_STRING_UC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
 
3818
#define DUK_HEAP_STRING_DEC_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
 
3819
#define DUK_HTHREAD_STRING_DEC_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
 
3820
#define DUK_HEAP_STRING_OBJ_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
 
3821
#define DUK_HTHREAD_STRING_OBJ_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
 
3822
#define DUK_HEAP_STRING_EMPTY_STRING(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
 
3823
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
 
3824
#define DUK_HEAP_STRING_GLOBAL(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
 
3825
#define DUK_HTHREAD_STRING_GLOBAL(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
 
3826
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
 
3827
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
 
3828
#define DUK_HEAP_STRING_JSON(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
 
3829
#define DUK_HTHREAD_STRING_JSON(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
 
3830
#define DUK_HEAP_STRING_MATH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
 
3831
#define DUK_HTHREAD_STRING_MATH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
 
3832
#define DUK_HEAP_STRING_UC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
 
3833
#define DUK_HTHREAD_STRING_UC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
 
3834
#define DUK_HEAP_STRING_REG_EXP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
 
3835
#define DUK_HTHREAD_STRING_REG_EXP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
 
3836
#define DUK_HEAP_STRING_DATE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
 
3837
#define DUK_HTHREAD_STRING_DATE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
 
3838
#define DUK_HEAP_STRING_UC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
 
3839
#define DUK_HTHREAD_STRING_UC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
 
3840
#define DUK_HEAP_STRING_UC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
 
3841
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
 
3842
#define DUK_HEAP_STRING_UC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
 
3843
#define DUK_HTHREAD_STRING_UC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
 
3844
#define DUK_HEAP_STRING_ARRAY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
 
3845
#define DUK_HTHREAD_STRING_ARRAY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
 
3846
#define DUK_HEAP_STRING_UC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
 
3847
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
 
3848
#define DUK_HEAP_STRING_UC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
 
3849
#define DUK_HTHREAD_STRING_UC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
 
3850
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
3851
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
3852
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
3853
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
3854
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
 
3855
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
 
3856
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
 
3857
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
 
3858
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
 
3859
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
 
3860
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
3861
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
3862
#define DUK_HEAP_STRING_TO_LOG_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
 
3863
#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
 
3864
#define DUK_HEAP_STRING_CLOG(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
 
3865
#define DUK_HTHREAD_STRING_CLOG(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
 
3866
#define DUK_HEAP_STRING_LC_L(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
 
3867
#define DUK_HTHREAD_STRING_LC_L(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
 
3868
#define DUK_HEAP_STRING_LC_N(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
 
3869
#define DUK_HTHREAD_STRING_LC_N(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
 
3870
#define DUK_HEAP_STRING_LC_FATAL(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
 
3871
#define DUK_HTHREAD_STRING_LC_FATAL(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
 
3872
#define DUK_HEAP_STRING_LC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
 
3873
#define DUK_HTHREAD_STRING_LC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
 
3874
#define DUK_HEAP_STRING_LC_WARN(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
 
3875
#define DUK_HTHREAD_STRING_LC_WARN(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
 
3876
#define DUK_HEAP_STRING_LC_DEBUG(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
 
3877
#define DUK_HTHREAD_STRING_LC_DEBUG(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
 
3878
#define DUK_HEAP_STRING_LC_TRACE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
 
3879
#define DUK_HTHREAD_STRING_LC_TRACE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
 
3880
#define DUK_HEAP_STRING_RAW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
 
3881
#define DUK_HTHREAD_STRING_RAW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
 
3882
#define DUK_HEAP_STRING_FMT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
 
3883
#define DUK_HTHREAD_STRING_FMT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
 
3884
#define DUK_HEAP_STRING_CURRENT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CURRENT)
 
3885
#define DUK_HTHREAD_STRING_CURRENT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CURRENT)
 
3886
#define DUK_HEAP_STRING_RESUME(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
 
3887
#define DUK_HTHREAD_STRING_RESUME(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
 
3888
#define DUK_HEAP_STRING_COMPACT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPACT)
 
3889
#define DUK_HTHREAD_STRING_COMPACT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPACT)
 
3890
#define DUK_HEAP_STRING_JSONC(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONC)
 
3891
#define DUK_HTHREAD_STRING_JSONC(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONC)
 
3892
#define DUK_HEAP_STRING_JSONX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONX)
 
3893
#define DUK_HTHREAD_STRING_JSONX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONX)
 
3894
#define DUK_HEAP_STRING_BASE64(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
 
3895
#define DUK_HTHREAD_STRING_BASE64(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
 
3896
#define DUK_HEAP_STRING_HEX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
 
3897
#define DUK_HTHREAD_STRING_HEX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
 
3898
#define DUK_HEAP_STRING_DEC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC)
 
3899
#define DUK_HTHREAD_STRING_DEC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC)
 
3900
#define DUK_HEAP_STRING_ENC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENC)
 
3901
#define DUK_HTHREAD_STRING_ENC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENC)
 
3902
#define DUK_HEAP_STRING_FIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FIN)
 
3903
#define DUK_HTHREAD_STRING_FIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FIN)
 
3904
#define DUK_HEAP_STRING_GC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GC)
 
3905
#define DUK_HTHREAD_STRING_GC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GC)
 
3906
#define DUK_HEAP_STRING_ACT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACT)
 
3907
#define DUK_HTHREAD_STRING_ACT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACT)
 
3908
#define DUK_HEAP_STRING_LINE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE)
 
3909
#define DUK_HTHREAD_STRING_LINE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE)
 
3910
#define DUK_HEAP_STRING_LC_INFO(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
 
3911
#define DUK_HTHREAD_STRING_LC_INFO(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
 
3912
#define DUK_HEAP_STRING_VERSION(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VERSION)
 
3913
#define DUK_HTHREAD_STRING_VERSION(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VERSION)
 
3914
#define DUK_HEAP_STRING_ENV(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
 
3915
#define DUK_HTHREAD_STRING_ENV(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
 
3916
#define DUK_HEAP_STRING_ERRTHROW(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRTHROW)
 
3917
#define DUK_HTHREAD_STRING_ERRTHROW(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRTHROW)
 
3918
#define DUK_HEAP_STRING_ERRCREATE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRCREATE)
 
3919
#define DUK_HTHREAD_STRING_ERRCREATE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRCREATE)
 
3920
#define DUK_HEAP_STRING_COMPILE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
 
3921
#define DUK_HTHREAD_STRING_COMPILE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
 
3922
#define DUK_HEAP_STRING_INT_REGBASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
 
3923
#define DUK_HTHREAD_STRING_INT_REGBASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
 
3924
#define DUK_HEAP_STRING_INT_THREAD(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
 
3925
#define DUK_HTHREAD_STRING_INT_THREAD(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
 
3926
#define DUK_HEAP_STRING_INT_FINALIZER(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
 
3927
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
 
3928
#define DUK_HEAP_STRING_INT_CALLEE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
 
3929
#define DUK_HTHREAD_STRING_INT_CALLEE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
 
3930
#define DUK_HEAP_STRING_INT_MAP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
 
3931
#define DUK_HTHREAD_STRING_INT_MAP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
 
3932
#define DUK_HEAP_STRING_INT_ARGS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
 
3933
#define DUK_HTHREAD_STRING_INT_ARGS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
 
3934
#define DUK_HEAP_STRING_INT_THIS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
 
3935
#define DUK_HTHREAD_STRING_INT_THIS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
 
3936
#define DUK_HEAP_STRING_INT_PC2LINE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
 
3937
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
 
3938
#define DUK_HEAP_STRING_INT_SOURCE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
 
3939
#define DUK_HTHREAD_STRING_INT_SOURCE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
 
3940
#define DUK_HEAP_STRING_INT_VARENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
 
3941
#define DUK_HTHREAD_STRING_INT_VARENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
 
3942
#define DUK_HEAP_STRING_INT_LEXENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
 
3943
#define DUK_HTHREAD_STRING_INT_LEXENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
 
3944
#define DUK_HEAP_STRING_INT_VARMAP(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
 
3945
#define DUK_HTHREAD_STRING_INT_VARMAP(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
 
3946
#define DUK_HEAP_STRING_INT_FORMALS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
 
3947
#define DUK_HTHREAD_STRING_INT_FORMALS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
 
3948
#define DUK_HEAP_STRING_INT_BYTECODE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
 
3949
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
 
3950
#define DUK_HEAP_STRING_INT_NEXT(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
 
3951
#define DUK_HTHREAD_STRING_INT_NEXT(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
 
3952
#define DUK_HEAP_STRING_INT_TARGET(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
 
3953
#define DUK_HTHREAD_STRING_INT_TARGET(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
 
3954
#define DUK_HEAP_STRING_INT_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
 
3955
#define DUK_HTHREAD_STRING_INT_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
 
3956
#define DUK_HEAP_STRING_LC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
 
3957
#define DUK_HTHREAD_STRING_LC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
 
3958
#define DUK_HEAP_STRING_LC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
 
3959
#define DUK_HTHREAD_STRING_LC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
 
3960
#define DUK_HEAP_STRING_TRACEDATA(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRACEDATA)
 
3961
#define DUK_HTHREAD_STRING_TRACEDATA(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRACEDATA)
 
3962
#define DUK_HEAP_STRING_LINE_NUMBER(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
 
3963
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
 
3964
#define DUK_HEAP_STRING_FILE_NAME(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
 
3965
#define DUK_HTHREAD_STRING_FILE_NAME(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
 
3966
#define DUK_HEAP_STRING_PC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
 
3967
#define DUK_HTHREAD_STRING_PC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
 
3968
#define DUK_HEAP_STRING_STACK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
 
3969
#define DUK_HTHREAD_STRING_STACK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
 
3970
#define DUK_HEAP_STRING_THROW_TYPE_ERROR(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW_TYPE_ERROR)
 
3971
#define DUK_HTHREAD_STRING_THROW_TYPE_ERROR(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW_TYPE_ERROR)
 
3972
#define DUK_HEAP_STRING_DUKTAPE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DUKTAPE)
 
3973
#define DUK_HTHREAD_STRING_DUKTAPE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DUKTAPE)
 
3974
#define DUK_HEAP_STRING_CALLEE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
 
3975
#define DUK_HTHREAD_STRING_CALLEE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
 
3976
#define DUK_HEAP_STRING_INVALID_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
 
3977
#define DUK_HTHREAD_STRING_INVALID_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
 
3978
#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
3979
#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
3980
#define DUK_HEAP_STRING_NEWLINE_TAB(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_TAB)
 
3981
#define DUK_HTHREAD_STRING_NEWLINE_TAB(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_TAB)
 
3982
#define DUK_HEAP_STRING_SPACE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
 
3983
#define DUK_HTHREAD_STRING_SPACE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
 
3984
#define DUK_HEAP_STRING_COMMA(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
 
3985
#define DUK_HTHREAD_STRING_COMMA(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
 
3986
#define DUK_HEAP_STRING_MINUS_ZERO(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
 
3987
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
 
3988
#define DUK_HEAP_STRING_PLUS_ZERO(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_ZERO)
 
3989
#define DUK_HTHREAD_STRING_PLUS_ZERO(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_ZERO)
 
3990
#define DUK_HEAP_STRING_ZERO(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ZERO)
 
3991
#define DUK_HTHREAD_STRING_ZERO(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ZERO)
 
3992
#define DUK_HEAP_STRING_MINUS_INFINITY(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
 
3993
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
 
3994
#define DUK_HEAP_STRING_PLUS_INFINITY(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_INFINITY)
 
3995
#define DUK_HTHREAD_STRING_PLUS_INFINITY(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_INFINITY)
 
3996
#define DUK_HEAP_STRING_INFINITY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
 
3997
#define DUK_HTHREAD_STRING_INFINITY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
 
3998
#define DUK_HEAP_STRING_LC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
 
3999
#define DUK_HTHREAD_STRING_LC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
 
4000
#define DUK_HEAP_STRING_LC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
 
4001
#define DUK_HTHREAD_STRING_LC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
 
4002
#define DUK_HEAP_STRING_LC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
 
4003
#define DUK_HTHREAD_STRING_LC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
 
4004
#define DUK_HEAP_STRING_LC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
 
4005
#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
 
4006
#define DUK_HEAP_STRING_UNDEFINED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNDEFINED)
 
4007
#define DUK_HTHREAD_STRING_UNDEFINED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNDEFINED)
 
4008
#define DUK_HEAP_STRING_STRINGIFY(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STRINGIFY)
 
4009
#define DUK_HTHREAD_STRING_STRINGIFY(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STRINGIFY)
 
4010
#define DUK_HEAP_STRING_TAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TAN)
 
4011
#define DUK_HTHREAD_STRING_TAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TAN)
 
4012
#define DUK_HEAP_STRING_SQRT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT)
 
4013
#define DUK_HTHREAD_STRING_SQRT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT)
 
4014
#define DUK_HEAP_STRING_SIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SIN)
 
4015
#define DUK_HTHREAD_STRING_SIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SIN)
 
4016
#define DUK_HEAP_STRING_ROUND(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ROUND)
 
4017
#define DUK_HTHREAD_STRING_ROUND(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ROUND)
 
4018
#define DUK_HEAP_STRING_RANDOM(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANDOM)
 
4019
#define DUK_HTHREAD_STRING_RANDOM(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANDOM)
 
4020
#define DUK_HEAP_STRING_POW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POW)
 
4021
#define DUK_HTHREAD_STRING_POW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POW)
 
4022
#define DUK_HEAP_STRING_MIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN)
 
4023
#define DUK_HTHREAD_STRING_MIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN)
 
4024
#define DUK_HEAP_STRING_MAX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX)
 
4025
#define DUK_HTHREAD_STRING_MAX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX)
 
4026
#define DUK_HEAP_STRING_LOG(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG)
 
4027
#define DUK_HTHREAD_STRING_LOG(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG)
 
4028
#define DUK_HEAP_STRING_FLOOR(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOOR)
 
4029
#define DUK_HTHREAD_STRING_FLOOR(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOOR)
 
4030
#define DUK_HEAP_STRING_EXP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXP)
 
4031
#define DUK_HTHREAD_STRING_EXP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXP)
 
4032
#define DUK_HEAP_STRING_COS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COS)
 
4033
#define DUK_HTHREAD_STRING_COS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COS)
 
4034
#define DUK_HEAP_STRING_CEIL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CEIL)
 
4035
#define DUK_HTHREAD_STRING_CEIL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CEIL)
 
4036
#define DUK_HEAP_STRING_ATAN2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN2)
 
4037
#define DUK_HTHREAD_STRING_ATAN2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN2)
 
4038
#define DUK_HEAP_STRING_ATAN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN)
 
4039
#define DUK_HTHREAD_STRING_ATAN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN)
 
4040
#define DUK_HEAP_STRING_ASIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ASIN)
 
4041
#define DUK_HTHREAD_STRING_ASIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ASIN)
 
4042
#define DUK_HEAP_STRING_ACOS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACOS)
 
4043
#define DUK_HTHREAD_STRING_ACOS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACOS)
 
4044
#define DUK_HEAP_STRING_ABS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ABS)
 
4045
#define DUK_HTHREAD_STRING_ABS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ABS)
 
4046
#define DUK_HEAP_STRING_SQRT2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT2)
 
4047
#define DUK_HTHREAD_STRING_SQRT2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT2)
 
4048
#define DUK_HEAP_STRING_SQRT1_2(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT1_2)
 
4049
#define DUK_HTHREAD_STRING_SQRT1_2(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT1_2)
 
4050
#define DUK_HEAP_STRING_PI(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PI)
 
4051
#define DUK_HTHREAD_STRING_PI(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PI)
 
4052
#define DUK_HEAP_STRING_LOG10E(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG10E)
 
4053
#define DUK_HTHREAD_STRING_LOG10E(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG10E)
 
4054
#define DUK_HEAP_STRING_LOG2E(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG2E)
 
4055
#define DUK_HTHREAD_STRING_LOG2E(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG2E)
 
4056
#define DUK_HEAP_STRING_LN2(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN2)
 
4057
#define DUK_HTHREAD_STRING_LN2(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN2)
 
4058
#define DUK_HEAP_STRING_LN10(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN10)
 
4059
#define DUK_HTHREAD_STRING_LN10(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN10)
 
4060
#define DUK_HEAP_STRING_E(heap)                                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_E)
 
4061
#define DUK_HTHREAD_STRING_E(thr)                                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_E)
 
4062
#define DUK_HEAP_STRING_MESSAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
 
4063
#define DUK_HTHREAD_STRING_MESSAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
 
4064
#define DUK_HEAP_STRING_NAME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
 
4065
#define DUK_HTHREAD_STRING_NAME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
 
4066
#define DUK_HEAP_STRING_INPUT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
 
4067
#define DUK_HTHREAD_STRING_INPUT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
 
4068
#define DUK_HEAP_STRING_INDEX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
 
4069
#define DUK_HTHREAD_STRING_INDEX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
 
4070
#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
4071
#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
4072
#define DUK_HEAP_STRING_LAST_INDEX(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
 
4073
#define DUK_HTHREAD_STRING_LAST_INDEX(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
 
4074
#define DUK_HEAP_STRING_MULTILINE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
 
4075
#define DUK_HTHREAD_STRING_MULTILINE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
 
4076
#define DUK_HEAP_STRING_IGNORE_CASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
 
4077
#define DUK_HTHREAD_STRING_IGNORE_CASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
 
4078
#define DUK_HEAP_STRING_SOURCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
 
4079
#define DUK_HTHREAD_STRING_SOURCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
 
4080
#define DUK_HEAP_STRING_TEST(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TEST)
 
4081
#define DUK_HTHREAD_STRING_TEST(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TEST)
 
4082
#define DUK_HEAP_STRING_EXEC(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXEC)
 
4083
#define DUK_HTHREAD_STRING_EXEC(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXEC)
 
4084
#define DUK_HEAP_STRING_TO_GMT_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
 
4085
#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
 
4086
#define DUK_HEAP_STRING_SET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_YEAR)
 
4087
#define DUK_HTHREAD_STRING_SET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_YEAR)
 
4088
#define DUK_HEAP_STRING_GET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_YEAR)
 
4089
#define DUK_HTHREAD_STRING_GET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_YEAR)
 
4090
#define DUK_HEAP_STRING_TO_JSON(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
 
4091
#define DUK_HTHREAD_STRING_TO_JSON(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
 
4092
#define DUK_HEAP_STRING_TO_ISO_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
 
4093
#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
 
4094
#define DUK_HEAP_STRING_TO_UTC_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
 
4095
#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
 
4096
#define DUK_HEAP_STRING_SET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
4097
#define DUK_HTHREAD_STRING_SET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
4098
#define DUK_HEAP_STRING_SET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_FULL_YEAR)
 
4099
#define DUK_HTHREAD_STRING_SET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_FULL_YEAR)
 
4100
#define DUK_HEAP_STRING_SET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MONTH)
 
4101
#define DUK_HTHREAD_STRING_SET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MONTH)
 
4102
#define DUK_HEAP_STRING_SET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MONTH)
 
4103
#define DUK_HTHREAD_STRING_SET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MONTH)
 
4104
#define DUK_HEAP_STRING_SET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_DATE)
 
4105
#define DUK_HTHREAD_STRING_SET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_DATE)
 
4106
#define DUK_HEAP_STRING_SET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_DATE)
 
4107
#define DUK_HTHREAD_STRING_SET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_DATE)
 
4108
#define DUK_HEAP_STRING_SET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_HOURS)
 
4109
#define DUK_HTHREAD_STRING_SET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_HOURS)
 
4110
#define DUK_HEAP_STRING_SET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_HOURS)
 
4111
#define DUK_HTHREAD_STRING_SET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_HOURS)
 
4112
#define DUK_HEAP_STRING_SET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MINUTES)
 
4113
#define DUK_HTHREAD_STRING_SET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MINUTES)
 
4114
#define DUK_HEAP_STRING_SET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MINUTES)
 
4115
#define DUK_HTHREAD_STRING_SET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MINUTES)
 
4116
#define DUK_HEAP_STRING_SET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_SECONDS)
 
4117
#define DUK_HTHREAD_STRING_SET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_SECONDS)
 
4118
#define DUK_HEAP_STRING_SET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_SECONDS)
 
4119
#define DUK_HTHREAD_STRING_SET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_SECONDS)
 
4120
#define DUK_HEAP_STRING_SET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
4121
#define DUK_HTHREAD_STRING_SET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
4122
#define DUK_HEAP_STRING_SET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MILLISECONDS)
 
4123
#define DUK_HTHREAD_STRING_SET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MILLISECONDS)
 
4124
#define DUK_HEAP_STRING_SET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_TIME)
 
4125
#define DUK_HTHREAD_STRING_SET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_TIME)
 
4126
#define DUK_HEAP_STRING_GET_TIMEZONE_OFFSET(heap)                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
4127
#define DUK_HTHREAD_STRING_GET_TIMEZONE_OFFSET(thr)                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
4128
#define DUK_HEAP_STRING_GET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
4129
#define DUK_HTHREAD_STRING_GET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
4130
#define DUK_HEAP_STRING_GET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MILLISECONDS)
 
4131
#define DUK_HTHREAD_STRING_GET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MILLISECONDS)
 
4132
#define DUK_HEAP_STRING_GET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_SECONDS)
 
4133
#define DUK_HTHREAD_STRING_GET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_SECONDS)
 
4134
#define DUK_HEAP_STRING_GET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_SECONDS)
 
4135
#define DUK_HTHREAD_STRING_GET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_SECONDS)
 
4136
#define DUK_HEAP_STRING_GET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MINUTES)
 
4137
#define DUK_HTHREAD_STRING_GET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MINUTES)
 
4138
#define DUK_HEAP_STRING_GET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MINUTES)
 
4139
#define DUK_HTHREAD_STRING_GET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MINUTES)
 
4140
#define DUK_HEAP_STRING_GET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_HOURS)
 
4141
#define DUK_HTHREAD_STRING_GET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_HOURS)
 
4142
#define DUK_HEAP_STRING_GET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_HOURS)
 
4143
#define DUK_HTHREAD_STRING_GET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_HOURS)
 
4144
#define DUK_HEAP_STRING_GET_UTC_DAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DAY)
 
4145
#define DUK_HTHREAD_STRING_GET_UTC_DAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DAY)
 
4146
#define DUK_HEAP_STRING_GET_DAY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DAY)
 
4147
#define DUK_HTHREAD_STRING_GET_DAY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DAY)
 
4148
#define DUK_HEAP_STRING_GET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DATE)
 
4149
#define DUK_HTHREAD_STRING_GET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DATE)
 
4150
#define DUK_HEAP_STRING_GET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DATE)
 
4151
#define DUK_HTHREAD_STRING_GET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DATE)
 
4152
#define DUK_HEAP_STRING_GET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MONTH)
 
4153
#define DUK_HTHREAD_STRING_GET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MONTH)
 
4154
#define DUK_HEAP_STRING_GET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MONTH)
 
4155
#define DUK_HTHREAD_STRING_GET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MONTH)
 
4156
#define DUK_HEAP_STRING_GET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
4157
#define DUK_HTHREAD_STRING_GET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
4158
#define DUK_HEAP_STRING_GET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_FULL_YEAR)
 
4159
#define DUK_HTHREAD_STRING_GET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_FULL_YEAR)
 
4160
#define DUK_HEAP_STRING_GET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIME)
 
4161
#define DUK_HTHREAD_STRING_GET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIME)
 
4162
#define DUK_HEAP_STRING_TO_LOCALE_TIME_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
4163
#define DUK_HTHREAD_STRING_TO_LOCALE_TIME_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
4164
#define DUK_HEAP_STRING_TO_LOCALE_DATE_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
4165
#define DUK_HTHREAD_STRING_TO_LOCALE_DATE_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
4166
#define DUK_HEAP_STRING_TO_TIME_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_TIME_STRING)
 
4167
#define DUK_HTHREAD_STRING_TO_TIME_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_TIME_STRING)
 
4168
#define DUK_HEAP_STRING_TO_DATE_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_DATE_STRING)
 
4169
#define DUK_HTHREAD_STRING_TO_DATE_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_DATE_STRING)
 
4170
#define DUK_HEAP_STRING_NOW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NOW)
 
4171
#define DUK_HTHREAD_STRING_NOW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NOW)
 
4172
#define DUK_HEAP_STRING_UTC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UTC)
 
4173
#define DUK_HTHREAD_STRING_UTC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UTC)
 
4174
#define DUK_HEAP_STRING_PARSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE)
 
4175
#define DUK_HTHREAD_STRING_PARSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE)
 
4176
#define DUK_HEAP_STRING_TO_PRECISION(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_PRECISION)
 
4177
#define DUK_HTHREAD_STRING_TO_PRECISION(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_PRECISION)
 
4178
#define DUK_HEAP_STRING_TO_EXPONENTIAL(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_EXPONENTIAL)
 
4179
#define DUK_HTHREAD_STRING_TO_EXPONENTIAL(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_EXPONENTIAL)
 
4180
#define DUK_HEAP_STRING_TO_FIXED(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_FIXED)
 
4181
#define DUK_HTHREAD_STRING_TO_FIXED(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_FIXED)
 
4182
#define DUK_HEAP_STRING_POSITIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POSITIVE_INFINITY)
 
4183
#define DUK_HTHREAD_STRING_POSITIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POSITIVE_INFINITY)
 
4184
#define DUK_HEAP_STRING_NEGATIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEGATIVE_INFINITY)
 
4185
#define DUK_HTHREAD_STRING_NEGATIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEGATIVE_INFINITY)
 
4186
#define DUK_HEAP_STRING_NAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
 
4187
#define DUK_HTHREAD_STRING_NAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
 
4188
#define DUK_HEAP_STRING_MIN_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN_VALUE)
 
4189
#define DUK_HTHREAD_STRING_MIN_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN_VALUE)
 
4190
#define DUK_HEAP_STRING_MAX_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX_VALUE)
 
4191
#define DUK_HTHREAD_STRING_MAX_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX_VALUE)
 
4192
#define DUK_HEAP_STRING_SUBSTR(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTR)
 
4193
#define DUK_HTHREAD_STRING_SUBSTR(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTR)
 
4194
#define DUK_HEAP_STRING_TRIM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRIM)
 
4195
#define DUK_HTHREAD_STRING_TRIM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRIM)
 
4196
#define DUK_HEAP_STRING_TO_LOCALE_UPPER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
4197
#define DUK_HTHREAD_STRING_TO_LOCALE_UPPER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
4198
#define DUK_HEAP_STRING_TO_UPPER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UPPER_CASE)
 
4199
#define DUK_HTHREAD_STRING_TO_UPPER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UPPER_CASE)
 
4200
#define DUK_HEAP_STRING_TO_LOCALE_LOWER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
4201
#define DUK_HTHREAD_STRING_TO_LOCALE_LOWER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
4202
#define DUK_HEAP_STRING_TO_LOWER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOWER_CASE)
 
4203
#define DUK_HTHREAD_STRING_TO_LOWER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOWER_CASE)
 
4204
#define DUK_HEAP_STRING_SUBSTRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTRING)
 
4205
#define DUK_HTHREAD_STRING_SUBSTRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTRING)
 
4206
#define DUK_HEAP_STRING_SPLIT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLIT)
 
4207
#define DUK_HTHREAD_STRING_SPLIT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLIT)
 
4208
#define DUK_HEAP_STRING_SEARCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEARCH)
 
4209
#define DUK_HTHREAD_STRING_SEARCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEARCH)
 
4210
#define DUK_HEAP_STRING_REPLACE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REPLACE)
 
4211
#define DUK_HTHREAD_STRING_REPLACE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REPLACE)
 
4212
#define DUK_HEAP_STRING_MATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATCH)
 
4213
#define DUK_HTHREAD_STRING_MATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATCH)
 
4214
#define DUK_HEAP_STRING_LOCALE_COMPARE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOCALE_COMPARE)
 
4215
#define DUK_HTHREAD_STRING_LOCALE_COMPARE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOCALE_COMPARE)
 
4216
#define DUK_HEAP_STRING_CHAR_CODE_AT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_CODE_AT)
 
4217
#define DUK_HTHREAD_STRING_CHAR_CODE_AT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_CODE_AT)
 
4218
#define DUK_HEAP_STRING_CHAR_AT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_AT)
 
4219
#define DUK_HTHREAD_STRING_CHAR_AT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_AT)
 
4220
#define DUK_HEAP_STRING_FROM_CHAR_CODE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FROM_CHAR_CODE)
 
4221
#define DUK_HTHREAD_STRING_FROM_CHAR_CODE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FROM_CHAR_CODE)
 
4222
#define DUK_HEAP_STRING_REDUCE_RIGHT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE_RIGHT)
 
4223
#define DUK_HTHREAD_STRING_REDUCE_RIGHT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE_RIGHT)
 
4224
#define DUK_HEAP_STRING_REDUCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE)
 
4225
#define DUK_HTHREAD_STRING_REDUCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE)
 
4226
#define DUK_HEAP_STRING_FILTER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILTER)
 
4227
#define DUK_HTHREAD_STRING_FILTER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILTER)
 
4228
#define DUK_HEAP_STRING_MAP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAP)
 
4229
#define DUK_HTHREAD_STRING_MAP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAP)
 
4230
#define DUK_HEAP_STRING_FOR_EACH(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR_EACH)
 
4231
#define DUK_HTHREAD_STRING_FOR_EACH(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR_EACH)
 
4232
#define DUK_HEAP_STRING_SOME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOME)
 
4233
#define DUK_HTHREAD_STRING_SOME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOME)
 
4234
#define DUK_HEAP_STRING_EVERY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVERY)
 
4235
#define DUK_HTHREAD_STRING_EVERY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVERY)
 
4236
#define DUK_HEAP_STRING_LAST_INDEX_OF(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX_OF)
 
4237
#define DUK_HTHREAD_STRING_LAST_INDEX_OF(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX_OF)
 
4238
#define DUK_HEAP_STRING_INDEX_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX_OF)
 
4239
#define DUK_HTHREAD_STRING_INDEX_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX_OF)
 
4240
#define DUK_HEAP_STRING_UNSHIFT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNSHIFT)
 
4241
#define DUK_HTHREAD_STRING_UNSHIFT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNSHIFT)
 
4242
#define DUK_HEAP_STRING_SPLICE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLICE)
 
4243
#define DUK_HTHREAD_STRING_SPLICE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLICE)
 
4244
#define DUK_HEAP_STRING_SORT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SORT)
 
4245
#define DUK_HTHREAD_STRING_SORT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SORT)
 
4246
#define DUK_HEAP_STRING_SLICE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SLICE)
 
4247
#define DUK_HTHREAD_STRING_SLICE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SLICE)
 
4248
#define DUK_HEAP_STRING_SHIFT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SHIFT)
 
4249
#define DUK_HTHREAD_STRING_SHIFT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SHIFT)
 
4250
#define DUK_HEAP_STRING_REVERSE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REVERSE)
 
4251
#define DUK_HTHREAD_STRING_REVERSE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REVERSE)
 
4252
#define DUK_HEAP_STRING_PUSH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUSH)
 
4253
#define DUK_HTHREAD_STRING_PUSH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUSH)
 
4254
#define DUK_HEAP_STRING_POP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POP)
 
4255
#define DUK_HTHREAD_STRING_POP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POP)
 
4256
#define DUK_HEAP_STRING_JOIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
 
4257
#define DUK_HTHREAD_STRING_JOIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
 
4258
#define DUK_HEAP_STRING_CONCAT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONCAT)
 
4259
#define DUK_HTHREAD_STRING_CONCAT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONCAT)
 
4260
#define DUK_HEAP_STRING_IS_ARRAY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_ARRAY)
 
4261
#define DUK_HTHREAD_STRING_IS_ARRAY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_ARRAY)
 
4262
#define DUK_HEAP_STRING_LC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
 
4263
#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
 
4264
#define DUK_HEAP_STRING_CALLER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
 
4265
#define DUK_HTHREAD_STRING_CALLER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
 
4266
#define DUK_HEAP_STRING_BIND(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BIND)
 
4267
#define DUK_HTHREAD_STRING_BIND(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BIND)
 
4268
#define DUK_HEAP_STRING_CALL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALL)
 
4269
#define DUK_HTHREAD_STRING_CALL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALL)
 
4270
#define DUK_HEAP_STRING_APPLY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
 
4271
#define DUK_HTHREAD_STRING_APPLY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
 
4272
#define DUK_HEAP_STRING_PROPERTY_IS_ENUMERABLE(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
4273
#define DUK_HTHREAD_STRING_PROPERTY_IS_ENUMERABLE(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
4274
#define DUK_HEAP_STRING_IS_PROTOTYPE_OF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_PROTOTYPE_OF)
 
4275
#define DUK_HTHREAD_STRING_IS_PROTOTYPE_OF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_PROTOTYPE_OF)
 
4276
#define DUK_HEAP_STRING_HAS_OWN_PROPERTY(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS_OWN_PROPERTY)
 
4277
#define DUK_HTHREAD_STRING_HAS_OWN_PROPERTY(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS_OWN_PROPERTY)
 
4278
#define DUK_HEAP_STRING_VALUE_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
 
4279
#define DUK_HTHREAD_STRING_VALUE_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
 
4280
#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
 
4281
#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
 
4282
#define DUK_HEAP_STRING_TO_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
 
4283
#define DUK_HTHREAD_STRING_TO_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
 
4284
#define DUK_HEAP_STRING_CONSTRUCTOR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
 
4285
#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
 
4286
#define DUK_HEAP_STRING_SET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
 
4287
#define DUK_HTHREAD_STRING_SET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
 
4288
#define DUK_HEAP_STRING_GET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
 
4289
#define DUK_HTHREAD_STRING_GET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
 
4290
#define DUK_HEAP_STRING_ENUMERABLE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
 
4291
#define DUK_HTHREAD_STRING_ENUMERABLE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
 
4292
#define DUK_HEAP_STRING_CONFIGURABLE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
 
4293
#define DUK_HTHREAD_STRING_CONFIGURABLE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
 
4294
#define DUK_HEAP_STRING_WRITABLE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
 
4295
#define DUK_HTHREAD_STRING_WRITABLE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
 
4296
#define DUK_HEAP_STRING_VALUE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
 
4297
#define DUK_HTHREAD_STRING_VALUE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
 
4298
#define DUK_HEAP_STRING_KEYS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_KEYS)
 
4299
#define DUK_HTHREAD_STRING_KEYS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_KEYS)
 
4300
#define DUK_HEAP_STRING_IS_EXTENSIBLE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_EXTENSIBLE)
 
4301
#define DUK_HTHREAD_STRING_IS_EXTENSIBLE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_EXTENSIBLE)
 
4302
#define DUK_HEAP_STRING_IS_FROZEN(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FROZEN)
 
4303
#define DUK_HTHREAD_STRING_IS_FROZEN(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FROZEN)
 
4304
#define DUK_HEAP_STRING_IS_SEALED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_SEALED)
 
4305
#define DUK_HTHREAD_STRING_IS_SEALED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_SEALED)
 
4306
#define DUK_HEAP_STRING_PREVENT_EXTENSIONS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PREVENT_EXTENSIONS)
 
4307
#define DUK_HTHREAD_STRING_PREVENT_EXTENSIONS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PREVENT_EXTENSIONS)
 
4308
#define DUK_HEAP_STRING_FREEZE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FREEZE)
 
4309
#define DUK_HTHREAD_STRING_FREEZE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FREEZE)
 
4310
#define DUK_HEAP_STRING_SEAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEAL)
 
4311
#define DUK_HTHREAD_STRING_SEAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEAL)
 
4312
#define DUK_HEAP_STRING_DEFINE_PROPERTIES(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTIES)
 
4313
#define DUK_HTHREAD_STRING_DEFINE_PROPERTIES(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTIES)
 
4314
#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
 
4315
#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
 
4316
#define DUK_HEAP_STRING_CREATE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CREATE)
 
4317
#define DUK_HTHREAD_STRING_CREATE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CREATE)
 
4318
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_NAMES(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
4319
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_NAMES(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
4320
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_DESCRIPTOR(heap)             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
4321
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_DESCRIPTOR(thr)           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
4322
#define DUK_HEAP_STRING_GET_PROTOTYPE_OF(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_PROTOTYPE_OF)
 
4323
#define DUK_HTHREAD_STRING_GET_PROTOTYPE_OF(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_PROTOTYPE_OF)
 
4324
#define DUK_HEAP_STRING_PROTOTYPE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
 
4325
#define DUK_HTHREAD_STRING_PROTOTYPE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
 
4326
#define DUK_HEAP_STRING_LENGTH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
 
4327
#define DUK_HTHREAD_STRING_LENGTH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
 
4328
#define DUK_HEAP_STRING_ALERT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ALERT)
 
4329
#define DUK_HTHREAD_STRING_ALERT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ALERT)
 
4330
#define DUK_HEAP_STRING_PRINT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRINT)
 
4331
#define DUK_HTHREAD_STRING_PRINT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRINT)
 
4332
#define DUK_HEAP_STRING_UNESCAPE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNESCAPE)
 
4333
#define DUK_HTHREAD_STRING_UNESCAPE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNESCAPE)
 
4334
#define DUK_HEAP_STRING_ESCAPE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPE)
 
4335
#define DUK_HTHREAD_STRING_ESCAPE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPE)
 
4336
#define DUK_HEAP_STRING_ENCODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
4337
#define DUK_HTHREAD_STRING_ENCODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
4338
#define DUK_HEAP_STRING_ENCODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI)
 
4339
#define DUK_HTHREAD_STRING_ENCODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI)
 
4340
#define DUK_HEAP_STRING_DECODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI_COMPONENT)
 
4341
#define DUK_HTHREAD_STRING_DECODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI_COMPONENT)
 
4342
#define DUK_HEAP_STRING_DECODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI)
 
4343
#define DUK_HTHREAD_STRING_DECODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI)
 
4344
#define DUK_HEAP_STRING_IS_FINITE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FINITE)
 
4345
#define DUK_HTHREAD_STRING_IS_FINITE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FINITE)
 
4346
#define DUK_HEAP_STRING_IS_NAN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_NAN)
 
4347
#define DUK_HTHREAD_STRING_IS_NAN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_NAN)
 
4348
#define DUK_HEAP_STRING_PARSE_FLOAT(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_FLOAT)
 
4349
#define DUK_HTHREAD_STRING_PARSE_FLOAT(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_FLOAT)
 
4350
#define DUK_HEAP_STRING_PARSE_INT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_INT)
 
4351
#define DUK_HTHREAD_STRING_PARSE_INT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_INT)
 
4352
#define DUK_HEAP_STRING_EVAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
 
4353
#define DUK_HTHREAD_STRING_EVAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
 
4354
#define DUK_HEAP_STRING_URI_ERROR(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_URI_ERROR)
 
4355
#define DUK_HTHREAD_STRING_URI_ERROR(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_URI_ERROR)
 
4356
#define DUK_HEAP_STRING_TYPE_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE_ERROR)
 
4357
#define DUK_HTHREAD_STRING_TYPE_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE_ERROR)
 
4358
#define DUK_HEAP_STRING_SYNTAX_ERROR(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SYNTAX_ERROR)
 
4359
#define DUK_HTHREAD_STRING_SYNTAX_ERROR(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SYNTAX_ERROR)
 
4360
#define DUK_HEAP_STRING_REFERENCE_ERROR(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REFERENCE_ERROR)
 
4361
#define DUK_HTHREAD_STRING_REFERENCE_ERROR(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REFERENCE_ERROR)
 
4362
#define DUK_HEAP_STRING_RANGE_ERROR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANGE_ERROR)
 
4363
#define DUK_HTHREAD_STRING_RANGE_ERROR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANGE_ERROR)
 
4364
#define DUK_HEAP_STRING_EVAL_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL_ERROR)
 
4365
#define DUK_HTHREAD_STRING_EVAL_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL_ERROR)
 
4366
#define DUK_HEAP_STRING_BREAK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
 
4367
#define DUK_HTHREAD_STRING_BREAK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
 
4368
#define DUK_HEAP_STRING_CASE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
 
4369
#define DUK_HTHREAD_STRING_CASE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
 
4370
#define DUK_HEAP_STRING_CATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
 
4371
#define DUK_HTHREAD_STRING_CATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
 
4372
#define DUK_HEAP_STRING_CONTINUE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
 
4373
#define DUK_HTHREAD_STRING_CONTINUE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
 
4374
#define DUK_HEAP_STRING_DEBUGGER(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
 
4375
#define DUK_HTHREAD_STRING_DEBUGGER(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
 
4376
#define DUK_HEAP_STRING_DEFAULT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
 
4377
#define DUK_HTHREAD_STRING_DEFAULT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
 
4378
#define DUK_HEAP_STRING_DELETE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
 
4379
#define DUK_HTHREAD_STRING_DELETE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
 
4380
#define DUK_HEAP_STRING_DO(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
 
4381
#define DUK_HTHREAD_STRING_DO(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
 
4382
#define DUK_HEAP_STRING_ELSE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
 
4383
#define DUK_HTHREAD_STRING_ELSE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
 
4384
#define DUK_HEAP_STRING_FINALLY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
 
4385
#define DUK_HTHREAD_STRING_FINALLY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
 
4386
#define DUK_HEAP_STRING_FOR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
 
4387
#define DUK_HTHREAD_STRING_FOR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
 
4388
#define DUK_HEAP_STRING_LC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
 
4389
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
 
4390
#define DUK_HEAP_STRING_IF(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
 
4391
#define DUK_HTHREAD_STRING_IF(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
 
4392
#define DUK_HEAP_STRING_IN(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
 
4393
#define DUK_HTHREAD_STRING_IN(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
 
4394
#define DUK_HEAP_STRING_INSTANCEOF(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
 
4395
#define DUK_HTHREAD_STRING_INSTANCEOF(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
 
4396
#define DUK_HEAP_STRING_NEW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
 
4397
#define DUK_HTHREAD_STRING_NEW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
 
4398
#define DUK_HEAP_STRING_RETURN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
 
4399
#define DUK_HTHREAD_STRING_RETURN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
 
4400
#define DUK_HEAP_STRING_SWITCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
 
4401
#define DUK_HTHREAD_STRING_SWITCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
 
4402
#define DUK_HEAP_STRING_THIS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
 
4403
#define DUK_HTHREAD_STRING_THIS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
 
4404
#define DUK_HEAP_STRING_THROW(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
 
4405
#define DUK_HTHREAD_STRING_THROW(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
 
4406
#define DUK_HEAP_STRING_TRY(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
 
4407
#define DUK_HTHREAD_STRING_TRY(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
 
4408
#define DUK_HEAP_STRING_TYPEOF(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
 
4409
#define DUK_HTHREAD_STRING_TYPEOF(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
 
4410
#define DUK_HEAP_STRING_VAR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
 
4411
#define DUK_HTHREAD_STRING_VAR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
 
4412
#define DUK_HEAP_STRING_VOID(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
 
4413
#define DUK_HTHREAD_STRING_VOID(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
 
4414
#define DUK_HEAP_STRING_WHILE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
 
4415
#define DUK_HTHREAD_STRING_WHILE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
 
4416
#define DUK_HEAP_STRING_WITH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
 
4417
#define DUK_HTHREAD_STRING_WITH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
 
4418
#define DUK_HEAP_STRING_CLASS(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
 
4419
#define DUK_HTHREAD_STRING_CLASS(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
 
4420
#define DUK_HEAP_STRING_CONST(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
 
4421
#define DUK_HTHREAD_STRING_CONST(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
 
4422
#define DUK_HEAP_STRING_ENUM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
 
4423
#define DUK_HTHREAD_STRING_ENUM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
 
4424
#define DUK_HEAP_STRING_EXPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
 
4425
#define DUK_HTHREAD_STRING_EXPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
 
4426
#define DUK_HEAP_STRING_EXTENDS(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
 
4427
#define DUK_HTHREAD_STRING_EXTENDS(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
 
4428
#define DUK_HEAP_STRING_IMPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
 
4429
#define DUK_HTHREAD_STRING_IMPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
 
4430
#define DUK_HEAP_STRING_SUPER(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
 
4431
#define DUK_HTHREAD_STRING_SUPER(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
 
4432
#define DUK_HEAP_STRING_NULL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NULL)
 
4433
#define DUK_HTHREAD_STRING_NULL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NULL)
 
4434
#define DUK_HEAP_STRING_TRUE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
 
4435
#define DUK_HTHREAD_STRING_TRUE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
 
4436
#define DUK_HEAP_STRING_FALSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
 
4437
#define DUK_HTHREAD_STRING_FALSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
 
4438
#define DUK_HEAP_STRING_IMPLEMENTS(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
 
4439
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
 
4440
#define DUK_HEAP_STRING_INTERFACE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
 
4441
#define DUK_HTHREAD_STRING_INTERFACE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
 
4442
#define DUK_HEAP_STRING_LET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
 
4443
#define DUK_HTHREAD_STRING_LET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
 
4444
#define DUK_HEAP_STRING_PACKAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
 
4445
#define DUK_HTHREAD_STRING_PACKAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
 
4446
#define DUK_HEAP_STRING_PRIVATE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
 
4447
#define DUK_HTHREAD_STRING_PRIVATE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
 
4448
#define DUK_HEAP_STRING_PROTECTED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
 
4449
#define DUK_HTHREAD_STRING_PROTECTED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
 
4450
#define DUK_HEAP_STRING_PUBLIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
 
4451
#define DUK_HTHREAD_STRING_PUBLIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
 
4452
#define DUK_HEAP_STRING_STATIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
 
4453
#define DUK_HTHREAD_STRING_STATIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
 
4454
#define DUK_HEAP_STRING_YIELD(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
 
4455
#define DUK_HTHREAD_STRING_YIELD(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
 
4456
 
 
4457
#define DUK_HEAP_NUM_STRINGS                                          323
 
4458
 
 
4459
#define DUK_STRIDX_START_RESERVED                                     278
 
4460
#define DUK_STRIDX_START_STRICT_RESERVED                              314
 
4461
#define DUK_STRIDX_END_RESERVED                                       323                            /* exclusive endpoint */
 
4462
 
 
4463
extern const duk_c_function duk_bi_native_functions[];
 
4464
extern const duk_uint8_t duk_builtins_data[];
 
4465
#ifdef DUK_USE_INITJS
 
4466
extern const duk_uint8_t duk_initjs_data[];
 
4467
#endif  /* DUK_USE_INITJS */
 
4468
 
 
4469
#define DUK_BUILTINS_DATA_LENGTH                                      1314
 
4470
#ifdef DUK_USE_INITJS
 
4471
#define DUK_INITJS_DATA_LENGTH                                        148
 
4472
#endif  /* DUK_USE_INITJS */
 
4473
 
 
4474
#define DUK_BIDX_GLOBAL                                               0
 
4475
#define DUK_BIDX_GLOBAL_ENV                                           1
 
4476
#define DUK_BIDX_OBJECT_CONSTRUCTOR                                   2
 
4477
#define DUK_BIDX_OBJECT_PROTOTYPE                                     3
 
4478
#define DUK_BIDX_FUNCTION_CONSTRUCTOR                                 4
 
4479
#define DUK_BIDX_FUNCTION_PROTOTYPE                                   5
 
4480
#define DUK_BIDX_ARRAY_CONSTRUCTOR                                    6
 
4481
#define DUK_BIDX_ARRAY_PROTOTYPE                                      7
 
4482
#define DUK_BIDX_STRING_CONSTRUCTOR                                   8
 
4483
#define DUK_BIDX_STRING_PROTOTYPE                                     9
 
4484
#define DUK_BIDX_BOOLEAN_CONSTRUCTOR                                  10
 
4485
#define DUK_BIDX_BOOLEAN_PROTOTYPE                                    11
 
4486
#define DUK_BIDX_NUMBER_CONSTRUCTOR                                   12
 
4487
#define DUK_BIDX_NUMBER_PROTOTYPE                                     13
 
4488
#define DUK_BIDX_DATE_CONSTRUCTOR                                     14
 
4489
#define DUK_BIDX_DATE_PROTOTYPE                                       15
 
4490
#define DUK_BIDX_REGEXP_CONSTRUCTOR                                   16
 
4491
#define DUK_BIDX_REGEXP_PROTOTYPE                                     17
 
4492
#define DUK_BIDX_ERROR_CONSTRUCTOR                                    18
 
4493
#define DUK_BIDX_ERROR_PROTOTYPE                                      19
 
4494
#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR                               20
 
4495
#define DUK_BIDX_EVAL_ERROR_PROTOTYPE                                 21
 
4496
#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR                              22
 
4497
#define DUK_BIDX_RANGE_ERROR_PROTOTYPE                                23
 
4498
#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR                          24
 
4499
#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE                            25
 
4500
#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR                             26
 
4501
#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE                               27
 
4502
#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR                               28
 
4503
#define DUK_BIDX_TYPE_ERROR_PROTOTYPE                                 29
 
4504
#define DUK_BIDX_URI_ERROR_CONSTRUCTOR                                30
 
4505
#define DUK_BIDX_URI_ERROR_PROTOTYPE                                  31
 
4506
#define DUK_BIDX_MATH                                                 32
 
4507
#define DUK_BIDX_JSON                                                 33
 
4508
#define DUK_BIDX_TYPE_ERROR_THROWER                                   34
 
4509
#define DUK_BIDX_DUKTAPE                                              35
 
4510
#define DUK_BIDX_THREAD_CONSTRUCTOR                                   36
 
4511
#define DUK_BIDX_THREAD_PROTOTYPE                                     37
 
4512
#define DUK_BIDX_BUFFER_CONSTRUCTOR                                   38
 
4513
#define DUK_BIDX_BUFFER_PROTOTYPE                                     39
 
4514
#define DUK_BIDX_POINTER_CONSTRUCTOR                                  40
 
4515
#define DUK_BIDX_POINTER_PROTOTYPE                                    41
 
4516
#define DUK_BIDX_LOGGER_CONSTRUCTOR                                   42
 
4517
#define DUK_BIDX_LOGGER_PROTOTYPE                                     43
 
4518
#define DUK_BIDX_DOUBLE_ERROR                                         44
 
4519
 
 
4520
#define DUK_NUM_BUILTINS                                              45
 
4521
 
 
4522
#elif defined(DUK_USE_DOUBLE_ME)
 
4523
extern const duk_uint8_t duk_strings_data[];
 
4524
 
 
4525
#define DUK_STRDATA_DATA_LENGTH                                       1854
 
4526
#define DUK_STRDATA_MAX_STRLEN                                        24
 
4527
 
 
4528
#define DUK_STRIDX_UC_LOGGER                                          0                              /* 'Logger' */
 
4529
#define DUK_STRIDX_UC_THREAD                                          1                              /* 'Thread' */
 
4530
#define DUK_STRIDX_UC_POINTER                                         2                              /* 'Pointer' */
 
4531
#define DUK_STRIDX_UC_BUFFER                                          3                              /* 'Buffer' */
 
4532
#define DUK_STRIDX_DEC_ENV                                            4                              /* 'DecEnv' */
 
4533
#define DUK_STRIDX_OBJ_ENV                                            5                              /* 'ObjEnv' */
 
4534
#define DUK_STRIDX_EMPTY_STRING                                       6                              /* '' */
 
4535
#define DUK_STRIDX_GLOBAL                                             7                              /* 'global' */
 
4536
#define DUK_STRIDX_UC_ARGUMENTS                                       8                              /* 'Arguments' */
 
4537
#define DUK_STRIDX_JSON                                               9                              /* 'JSON' */
 
4538
#define DUK_STRIDX_MATH                                               10                             /* 'Math' */
 
4539
#define DUK_STRIDX_UC_ERROR                                           11                             /* 'Error' */
 
4540
#define DUK_STRIDX_REG_EXP                                            12                             /* 'RegExp' */
 
4541
#define DUK_STRIDX_DATE                                               13                             /* 'Date' */
 
4542
#define DUK_STRIDX_UC_NUMBER                                          14                             /* 'Number' */
 
4543
#define DUK_STRIDX_UC_BOOLEAN                                         15                             /* 'Boolean' */
 
4544
#define DUK_STRIDX_UC_STRING                                          16                             /* 'String' */
 
4545
#define DUK_STRIDX_ARRAY                                              17                             /* 'Array' */
 
4546
#define DUK_STRIDX_UC_FUNCTION                                        18                             /* 'Function' */
 
4547
#define DUK_STRIDX_UC_OBJECT                                          19                             /* 'Object' */
 
4548
#define DUK_STRIDX_JSON_EXT_FUNCTION2                                 20                             /* '{_func:true}' */
 
4549
#define DUK_STRIDX_JSON_EXT_FUNCTION1                                 21                             /* '{"_func":true}' */
 
4550
#define DUK_STRIDX_JSON_EXT_NEGINF                                    22                             /* '{"_ninf":true}' */
 
4551
#define DUK_STRIDX_JSON_EXT_POSINF                                    23                             /* '{"_inf":true}' */
 
4552
#define DUK_STRIDX_JSON_EXT_NAN                                       24                             /* '{"_nan":true}' */
 
4553
#define DUK_STRIDX_JSON_EXT_UNDEFINED                                 25                             /* '{"_undef":true}' */
 
4554
#define DUK_STRIDX_TO_LOG_STRING                                      26                             /* 'toLogString' */
 
4555
#define DUK_STRIDX_CLOG                                               27                             /* 'clog' */
 
4556
#define DUK_STRIDX_LC_L                                               28                             /* 'l' */
 
4557
#define DUK_STRIDX_LC_N                                               29                             /* 'n' */
 
4558
#define DUK_STRIDX_LC_FATAL                                           30                             /* 'fatal' */
 
4559
#define DUK_STRIDX_LC_ERROR                                           31                             /* 'error' */
 
4560
#define DUK_STRIDX_LC_WARN                                            32                             /* 'warn' */
 
4561
#define DUK_STRIDX_LC_DEBUG                                           33                             /* 'debug' */
 
4562
#define DUK_STRIDX_LC_TRACE                                           34                             /* 'trace' */
 
4563
#define DUK_STRIDX_RAW                                                35                             /* 'raw' */
 
4564
#define DUK_STRIDX_FMT                                                36                             /* 'fmt' */
 
4565
#define DUK_STRIDX_CURRENT                                            37                             /* 'current' */
 
4566
#define DUK_STRIDX_RESUME                                             38                             /* 'resume' */
 
4567
#define DUK_STRIDX_COMPACT                                            39                             /* 'compact' */
 
4568
#define DUK_STRIDX_JSONC                                              40                             /* 'jsonc' */
 
4569
#define DUK_STRIDX_JSONX                                              41                             /* 'jsonx' */
 
4570
#define DUK_STRIDX_BASE64                                             42                             /* 'base64' */
 
4571
#define DUK_STRIDX_HEX                                                43                             /* 'hex' */
 
4572
#define DUK_STRIDX_DEC                                                44                             /* 'dec' */
 
4573
#define DUK_STRIDX_ENC                                                45                             /* 'enc' */
 
4574
#define DUK_STRIDX_FIN                                                46                             /* 'fin' */
 
4575
#define DUK_STRIDX_GC                                                 47                             /* 'gc' */
 
4576
#define DUK_STRIDX_ACT                                                48                             /* 'act' */
 
4577
#define DUK_STRIDX_LINE                                               49                             /* 'line' */
 
4578
#define DUK_STRIDX_LC_INFO                                            50                             /* 'info' */
 
4579
#define DUK_STRIDX_VERSION                                            51                             /* 'version' */
 
4580
#define DUK_STRIDX_ENV                                                52                             /* 'env' */
 
4581
#define DUK_STRIDX_ERRTHROW                                           53                             /* 'errthrow' */
 
4582
#define DUK_STRIDX_ERRCREATE                                          54                             /* 'errcreate' */
 
4583
#define DUK_STRIDX_COMPILE                                            55                             /* 'compile' */
 
4584
#define DUK_STRIDX_INT_REGBASE                                        56                             /* '\x00regbase' */
 
4585
#define DUK_STRIDX_INT_THREAD                                         57                             /* '\x00thread' */
 
4586
#define DUK_STRIDX_INT_FINALIZER                                      58                             /* '\x00finalizer' */
 
4587
#define DUK_STRIDX_INT_CALLEE                                         59                             /* '\x00callee' */
 
4588
#define DUK_STRIDX_INT_MAP                                            60                             /* '\x00map' */
 
4589
#define DUK_STRIDX_INT_ARGS                                           61                             /* '\x00args' */
 
4590
#define DUK_STRIDX_INT_THIS                                           62                             /* '\x00this' */
 
4591
#define DUK_STRIDX_INT_PC2LINE                                        63                             /* '\x00pc2line' */
 
4592
#define DUK_STRIDX_INT_SOURCE                                         64                             /* '\x00source' */
 
4593
#define DUK_STRIDX_INT_VARENV                                         65                             /* '\x00varenv' */
 
4594
#define DUK_STRIDX_INT_LEXENV                                         66                             /* '\x00lexenv' */
 
4595
#define DUK_STRIDX_INT_VARMAP                                         67                             /* '\x00varmap' */
 
4596
#define DUK_STRIDX_INT_FORMALS                                        68                             /* '\x00formals' */
 
4597
#define DUK_STRIDX_INT_BYTECODE                                       69                             /* '\x00bytecode' */
 
4598
#define DUK_STRIDX_INT_NEXT                                           70                             /* '\x00next' */
 
4599
#define DUK_STRIDX_INT_TARGET                                         71                             /* '\x00target' */
 
4600
#define DUK_STRIDX_INT_VALUE                                          72                             /* '\x00value' */
 
4601
#define DUK_STRIDX_LC_POINTER                                         73                             /* 'pointer' */
 
4602
#define DUK_STRIDX_LC_BUFFER                                          74                             /* 'buffer' */
 
4603
#define DUK_STRIDX_TRACEDATA                                          75                             /* 'tracedata' */
 
4604
#define DUK_STRIDX_LINE_NUMBER                                        76                             /* 'lineNumber' */
 
4605
#define DUK_STRIDX_FILE_NAME                                          77                             /* 'fileName' */
 
4606
#define DUK_STRIDX_PC                                                 78                             /* 'pc' */
 
4607
#define DUK_STRIDX_STACK                                              79                             /* 'stack' */
 
4608
#define DUK_STRIDX_THROW_TYPE_ERROR                                   80                             /* 'ThrowTypeError' */
 
4609
#define DUK_STRIDX_DUKTAPE                                            81                             /* 'Duktape' */
 
4610
#define DUK_STRIDX_CALLEE                                             82                             /* 'callee' */
 
4611
#define DUK_STRIDX_INVALID_DATE                                       83                             /* 'Invalid Date' */
 
4612
#define DUK_STRIDX_BRACKETED_ELLIPSIS                                 84                             /* '[...]' */
 
4613
#define DUK_STRIDX_NEWLINE_TAB                                        85                             /* '\n\t' */
 
4614
#define DUK_STRIDX_SPACE                                              86                             /* ' ' */
 
4615
#define DUK_STRIDX_COMMA                                              87                             /* ',' */
 
4616
#define DUK_STRIDX_MINUS_ZERO                                         88                             /* '-0' */
 
4617
#define DUK_STRIDX_PLUS_ZERO                                          89                             /* '+0' */
 
4618
#define DUK_STRIDX_ZERO                                               90                             /* '0' */
 
4619
#define DUK_STRIDX_MINUS_INFINITY                                     91                             /* '-Infinity' */
 
4620
#define DUK_STRIDX_PLUS_INFINITY                                      92                             /* '+Infinity' */
 
4621
#define DUK_STRIDX_INFINITY                                           93                             /* 'Infinity' */
 
4622
#define DUK_STRIDX_LC_OBJECT                                          94                             /* 'object' */
 
4623
#define DUK_STRIDX_LC_STRING                                          95                             /* 'string' */
 
4624
#define DUK_STRIDX_LC_NUMBER                                          96                             /* 'number' */
 
4625
#define DUK_STRIDX_LC_BOOLEAN                                         97                             /* 'boolean' */
 
4626
#define DUK_STRIDX_UNDEFINED                                          98                             /* 'undefined' */
 
4627
#define DUK_STRIDX_STRINGIFY                                          99                             /* 'stringify' */
 
4628
#define DUK_STRIDX_TAN                                                100                            /* 'tan' */
 
4629
#define DUK_STRIDX_SQRT                                               101                            /* 'sqrt' */
 
4630
#define DUK_STRIDX_SIN                                                102                            /* 'sin' */
 
4631
#define DUK_STRIDX_ROUND                                              103                            /* 'round' */
 
4632
#define DUK_STRIDX_RANDOM                                             104                            /* 'random' */
 
4633
#define DUK_STRIDX_POW                                                105                            /* 'pow' */
 
4634
#define DUK_STRIDX_MIN                                                106                            /* 'min' */
 
4635
#define DUK_STRIDX_MAX                                                107                            /* 'max' */
 
4636
#define DUK_STRIDX_LOG                                                108                            /* 'log' */
 
4637
#define DUK_STRIDX_FLOOR                                              109                            /* 'floor' */
 
4638
#define DUK_STRIDX_EXP                                                110                            /* 'exp' */
 
4639
#define DUK_STRIDX_COS                                                111                            /* 'cos' */
 
4640
#define DUK_STRIDX_CEIL                                               112                            /* 'ceil' */
 
4641
#define DUK_STRIDX_ATAN2                                              113                            /* 'atan2' */
 
4642
#define DUK_STRIDX_ATAN                                               114                            /* 'atan' */
 
4643
#define DUK_STRIDX_ASIN                                               115                            /* 'asin' */
 
4644
#define DUK_STRIDX_ACOS                                               116                            /* 'acos' */
 
4645
#define DUK_STRIDX_ABS                                                117                            /* 'abs' */
 
4646
#define DUK_STRIDX_SQRT2                                              118                            /* 'SQRT2' */
 
4647
#define DUK_STRIDX_SQRT1_2                                            119                            /* 'SQRT1_2' */
 
4648
#define DUK_STRIDX_PI                                                 120                            /* 'PI' */
 
4649
#define DUK_STRIDX_LOG10E                                             121                            /* 'LOG10E' */
 
4650
#define DUK_STRIDX_LOG2E                                              122                            /* 'LOG2E' */
 
4651
#define DUK_STRIDX_LN2                                                123                            /* 'LN2' */
 
4652
#define DUK_STRIDX_LN10                                               124                            /* 'LN10' */
 
4653
#define DUK_STRIDX_E                                                  125                            /* 'E' */
 
4654
#define DUK_STRIDX_MESSAGE                                            126                            /* 'message' */
 
4655
#define DUK_STRIDX_NAME                                               127                            /* 'name' */
 
4656
#define DUK_STRIDX_INPUT                                              128                            /* 'input' */
 
4657
#define DUK_STRIDX_INDEX                                              129                            /* 'index' */
 
4658
#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP                               130                            /* '(?:)' */
 
4659
#define DUK_STRIDX_LAST_INDEX                                         131                            /* 'lastIndex' */
 
4660
#define DUK_STRIDX_MULTILINE                                          132                            /* 'multiline' */
 
4661
#define DUK_STRIDX_IGNORE_CASE                                        133                            /* 'ignoreCase' */
 
4662
#define DUK_STRIDX_SOURCE                                             134                            /* 'source' */
 
4663
#define DUK_STRIDX_TEST                                               135                            /* 'test' */
 
4664
#define DUK_STRIDX_EXEC                                               136                            /* 'exec' */
 
4665
#define DUK_STRIDX_TO_GMT_STRING                                      137                            /* 'toGMTString' */
 
4666
#define DUK_STRIDX_SET_YEAR                                           138                            /* 'setYear' */
 
4667
#define DUK_STRIDX_GET_YEAR                                           139                            /* 'getYear' */
 
4668
#define DUK_STRIDX_TO_JSON                                            140                            /* 'toJSON' */
 
4669
#define DUK_STRIDX_TO_ISO_STRING                                      141                            /* 'toISOString' */
 
4670
#define DUK_STRIDX_TO_UTC_STRING                                      142                            /* 'toUTCString' */
 
4671
#define DUK_STRIDX_SET_UTC_FULL_YEAR                                  143                            /* 'setUTCFullYear' */
 
4672
#define DUK_STRIDX_SET_FULL_YEAR                                      144                            /* 'setFullYear' */
 
4673
#define DUK_STRIDX_SET_UTC_MONTH                                      145                            /* 'setUTCMonth' */
 
4674
#define DUK_STRIDX_SET_MONTH                                          146                            /* 'setMonth' */
 
4675
#define DUK_STRIDX_SET_UTC_DATE                                       147                            /* 'setUTCDate' */
 
4676
#define DUK_STRIDX_SET_DATE                                           148                            /* 'setDate' */
 
4677
#define DUK_STRIDX_SET_UTC_HOURS                                      149                            /* 'setUTCHours' */
 
4678
#define DUK_STRIDX_SET_HOURS                                          150                            /* 'setHours' */
 
4679
#define DUK_STRIDX_SET_UTC_MINUTES                                    151                            /* 'setUTCMinutes' */
 
4680
#define DUK_STRIDX_SET_MINUTES                                        152                            /* 'setMinutes' */
 
4681
#define DUK_STRIDX_SET_UTC_SECONDS                                    153                            /* 'setUTCSeconds' */
 
4682
#define DUK_STRIDX_SET_SECONDS                                        154                            /* 'setSeconds' */
 
4683
#define DUK_STRIDX_SET_UTC_MILLISECONDS                               155                            /* 'setUTCMilliseconds' */
 
4684
#define DUK_STRIDX_SET_MILLISECONDS                                   156                            /* 'setMilliseconds' */
 
4685
#define DUK_STRIDX_SET_TIME                                           157                            /* 'setTime' */
 
4686
#define DUK_STRIDX_GET_TIMEZONE_OFFSET                                158                            /* 'getTimezoneOffset' */
 
4687
#define DUK_STRIDX_GET_UTC_MILLISECONDS                               159                            /* 'getUTCMilliseconds' */
 
4688
#define DUK_STRIDX_GET_MILLISECONDS                                   160                            /* 'getMilliseconds' */
 
4689
#define DUK_STRIDX_GET_UTC_SECONDS                                    161                            /* 'getUTCSeconds' */
 
4690
#define DUK_STRIDX_GET_SECONDS                                        162                            /* 'getSeconds' */
 
4691
#define DUK_STRIDX_GET_UTC_MINUTES                                    163                            /* 'getUTCMinutes' */
 
4692
#define DUK_STRIDX_GET_MINUTES                                        164                            /* 'getMinutes' */
 
4693
#define DUK_STRIDX_GET_UTC_HOURS                                      165                            /* 'getUTCHours' */
 
4694
#define DUK_STRIDX_GET_HOURS                                          166                            /* 'getHours' */
 
4695
#define DUK_STRIDX_GET_UTC_DAY                                        167                            /* 'getUTCDay' */
 
4696
#define DUK_STRIDX_GET_DAY                                            168                            /* 'getDay' */
 
4697
#define DUK_STRIDX_GET_UTC_DATE                                       169                            /* 'getUTCDate' */
 
4698
#define DUK_STRIDX_GET_DATE                                           170                            /* 'getDate' */
 
4699
#define DUK_STRIDX_GET_UTC_MONTH                                      171                            /* 'getUTCMonth' */
 
4700
#define DUK_STRIDX_GET_MONTH                                          172                            /* 'getMonth' */
 
4701
#define DUK_STRIDX_GET_UTC_FULL_YEAR                                  173                            /* 'getUTCFullYear' */
 
4702
#define DUK_STRIDX_GET_FULL_YEAR                                      174                            /* 'getFullYear' */
 
4703
#define DUK_STRIDX_GET_TIME                                           175                            /* 'getTime' */
 
4704
#define DUK_STRIDX_TO_LOCALE_TIME_STRING                              176                            /* 'toLocaleTimeString' */
 
4705
#define DUK_STRIDX_TO_LOCALE_DATE_STRING                              177                            /* 'toLocaleDateString' */
 
4706
#define DUK_STRIDX_TO_TIME_STRING                                     178                            /* 'toTimeString' */
 
4707
#define DUK_STRIDX_TO_DATE_STRING                                     179                            /* 'toDateString' */
 
4708
#define DUK_STRIDX_NOW                                                180                            /* 'now' */
 
4709
#define DUK_STRIDX_UTC                                                181                            /* 'UTC' */
 
4710
#define DUK_STRIDX_PARSE                                              182                            /* 'parse' */
 
4711
#define DUK_STRIDX_TO_PRECISION                                       183                            /* 'toPrecision' */
 
4712
#define DUK_STRIDX_TO_EXPONENTIAL                                     184                            /* 'toExponential' */
 
4713
#define DUK_STRIDX_TO_FIXED                                           185                            /* 'toFixed' */
 
4714
#define DUK_STRIDX_POSITIVE_INFINITY                                  186                            /* 'POSITIVE_INFINITY' */
 
4715
#define DUK_STRIDX_NEGATIVE_INFINITY                                  187                            /* 'NEGATIVE_INFINITY' */
 
4716
#define DUK_STRIDX_NAN                                                188                            /* 'NaN' */
 
4717
#define DUK_STRIDX_MIN_VALUE                                          189                            /* 'MIN_VALUE' */
 
4718
#define DUK_STRIDX_MAX_VALUE                                          190                            /* 'MAX_VALUE' */
 
4719
#define DUK_STRIDX_SUBSTR                                             191                            /* 'substr' */
 
4720
#define DUK_STRIDX_TRIM                                               192                            /* 'trim' */
 
4721
#define DUK_STRIDX_TO_LOCALE_UPPER_CASE                               193                            /* 'toLocaleUpperCase' */
 
4722
#define DUK_STRIDX_TO_UPPER_CASE                                      194                            /* 'toUpperCase' */
 
4723
#define DUK_STRIDX_TO_LOCALE_LOWER_CASE                               195                            /* 'toLocaleLowerCase' */
 
4724
#define DUK_STRIDX_TO_LOWER_CASE                                      196                            /* 'toLowerCase' */
 
4725
#define DUK_STRIDX_SUBSTRING                                          197                            /* 'substring' */
 
4726
#define DUK_STRIDX_SPLIT                                              198                            /* 'split' */
 
4727
#define DUK_STRIDX_SEARCH                                             199                            /* 'search' */
 
4728
#define DUK_STRIDX_REPLACE                                            200                            /* 'replace' */
 
4729
#define DUK_STRIDX_MATCH                                              201                            /* 'match' */
 
4730
#define DUK_STRIDX_LOCALE_COMPARE                                     202                            /* 'localeCompare' */
 
4731
#define DUK_STRIDX_CHAR_CODE_AT                                       203                            /* 'charCodeAt' */
 
4732
#define DUK_STRIDX_CHAR_AT                                            204                            /* 'charAt' */
 
4733
#define DUK_STRIDX_FROM_CHAR_CODE                                     205                            /* 'fromCharCode' */
 
4734
#define DUK_STRIDX_REDUCE_RIGHT                                       206                            /* 'reduceRight' */
 
4735
#define DUK_STRIDX_REDUCE                                             207                            /* 'reduce' */
 
4736
#define DUK_STRIDX_FILTER                                             208                            /* 'filter' */
 
4737
#define DUK_STRIDX_MAP                                                209                            /* 'map' */
 
4738
#define DUK_STRIDX_FOR_EACH                                           210                            /* 'forEach' */
 
4739
#define DUK_STRIDX_SOME                                               211                            /* 'some' */
 
4740
#define DUK_STRIDX_EVERY                                              212                            /* 'every' */
 
4741
#define DUK_STRIDX_LAST_INDEX_OF                                      213                            /* 'lastIndexOf' */
 
4742
#define DUK_STRIDX_INDEX_OF                                           214                            /* 'indexOf' */
 
4743
#define DUK_STRIDX_UNSHIFT                                            215                            /* 'unshift' */
 
4744
#define DUK_STRIDX_SPLICE                                             216                            /* 'splice' */
 
4745
#define DUK_STRIDX_SORT                                               217                            /* 'sort' */
 
4746
#define DUK_STRIDX_SLICE                                              218                            /* 'slice' */
 
4747
#define DUK_STRIDX_SHIFT                                              219                            /* 'shift' */
 
4748
#define DUK_STRIDX_REVERSE                                            220                            /* 'reverse' */
 
4749
#define DUK_STRIDX_PUSH                                               221                            /* 'push' */
 
4750
#define DUK_STRIDX_POP                                                222                            /* 'pop' */
 
4751
#define DUK_STRIDX_JOIN                                               223                            /* 'join' */
 
4752
#define DUK_STRIDX_CONCAT                                             224                            /* 'concat' */
 
4753
#define DUK_STRIDX_IS_ARRAY                                           225                            /* 'isArray' */
 
4754
#define DUK_STRIDX_LC_ARGUMENTS                                       226                            /* 'arguments' */
 
4755
#define DUK_STRIDX_CALLER                                             227                            /* 'caller' */
 
4756
#define DUK_STRIDX_BIND                                               228                            /* 'bind' */
 
4757
#define DUK_STRIDX_CALL                                               229                            /* 'call' */
 
4758
#define DUK_STRIDX_APPLY                                              230                            /* 'apply' */
 
4759
#define DUK_STRIDX_PROPERTY_IS_ENUMERABLE                             231                            /* 'propertyIsEnumerable' */
 
4760
#define DUK_STRIDX_IS_PROTOTYPE_OF                                    232                            /* 'isPrototypeOf' */
 
4761
#define DUK_STRIDX_HAS_OWN_PROPERTY                                   233                            /* 'hasOwnProperty' */
 
4762
#define DUK_STRIDX_VALUE_OF                                           234                            /* 'valueOf' */
 
4763
#define DUK_STRIDX_TO_LOCALE_STRING                                   235                            /* 'toLocaleString' */
 
4764
#define DUK_STRIDX_TO_STRING                                          236                            /* 'toString' */
 
4765
#define DUK_STRIDX_CONSTRUCTOR                                        237                            /* 'constructor' */
 
4766
#define DUK_STRIDX_SET                                                238                            /* 'set' */
 
4767
#define DUK_STRIDX_GET                                                239                            /* 'get' */
 
4768
#define DUK_STRIDX_ENUMERABLE                                         240                            /* 'enumerable' */
 
4769
#define DUK_STRIDX_CONFIGURABLE                                       241                            /* 'configurable' */
 
4770
#define DUK_STRIDX_WRITABLE                                           242                            /* 'writable' */
 
4771
#define DUK_STRIDX_VALUE                                              243                            /* 'value' */
 
4772
#define DUK_STRIDX_KEYS                                               244                            /* 'keys' */
 
4773
#define DUK_STRIDX_IS_EXTENSIBLE                                      245                            /* 'isExtensible' */
 
4774
#define DUK_STRIDX_IS_FROZEN                                          246                            /* 'isFrozen' */
 
4775
#define DUK_STRIDX_IS_SEALED                                          247                            /* 'isSealed' */
 
4776
#define DUK_STRIDX_PREVENT_EXTENSIONS                                 248                            /* 'preventExtensions' */
 
4777
#define DUK_STRIDX_FREEZE                                             249                            /* 'freeze' */
 
4778
#define DUK_STRIDX_SEAL                                               250                            /* 'seal' */
 
4779
#define DUK_STRIDX_DEFINE_PROPERTIES                                  251                            /* 'defineProperties' */
 
4780
#define DUK_STRIDX_DEFINE_PROPERTY                                    252                            /* 'defineProperty' */
 
4781
#define DUK_STRIDX_CREATE                                             253                            /* 'create' */
 
4782
#define DUK_STRIDX_GET_OWN_PROPERTY_NAMES                             254                            /* 'getOwnPropertyNames' */
 
4783
#define DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR                        255                            /* 'getOwnPropertyDescriptor' */
 
4784
#define DUK_STRIDX_GET_PROTOTYPE_OF                                   256                            /* 'getPrototypeOf' */
 
4785
#define DUK_STRIDX_PROTOTYPE                                          257                            /* 'prototype' */
 
4786
#define DUK_STRIDX_LENGTH                                             258                            /* 'length' */
 
4787
#define DUK_STRIDX_ALERT                                              259                            /* 'alert' */
 
4788
#define DUK_STRIDX_PRINT                                              260                            /* 'print' */
 
4789
#define DUK_STRIDX_UNESCAPE                                           261                            /* 'unescape' */
 
4790
#define DUK_STRIDX_ESCAPE                                             262                            /* 'escape' */
 
4791
#define DUK_STRIDX_ENCODE_URI_COMPONENT                               263                            /* 'encodeURIComponent' */
 
4792
#define DUK_STRIDX_ENCODE_URI                                         264                            /* 'encodeURI' */
 
4793
#define DUK_STRIDX_DECODE_URI_COMPONENT                               265                            /* 'decodeURIComponent' */
 
4794
#define DUK_STRIDX_DECODE_URI                                         266                            /* 'decodeURI' */
 
4795
#define DUK_STRIDX_IS_FINITE                                          267                            /* 'isFinite' */
 
4796
#define DUK_STRIDX_IS_NAN                                             268                            /* 'isNaN' */
 
4797
#define DUK_STRIDX_PARSE_FLOAT                                        269                            /* 'parseFloat' */
 
4798
#define DUK_STRIDX_PARSE_INT                                          270                            /* 'parseInt' */
 
4799
#define DUK_STRIDX_EVAL                                               271                            /* 'eval' */
 
4800
#define DUK_STRIDX_URI_ERROR                                          272                            /* 'URIError' */
 
4801
#define DUK_STRIDX_TYPE_ERROR                                         273                            /* 'TypeError' */
 
4802
#define DUK_STRIDX_SYNTAX_ERROR                                       274                            /* 'SyntaxError' */
 
4803
#define DUK_STRIDX_REFERENCE_ERROR                                    275                            /* 'ReferenceError' */
 
4804
#define DUK_STRIDX_RANGE_ERROR                                        276                            /* 'RangeError' */
 
4805
#define DUK_STRIDX_EVAL_ERROR                                         277                            /* 'EvalError' */
 
4806
#define DUK_STRIDX_BREAK                                              278                            /* 'break' */
 
4807
#define DUK_STRIDX_CASE                                               279                            /* 'case' */
 
4808
#define DUK_STRIDX_CATCH                                              280                            /* 'catch' */
 
4809
#define DUK_STRIDX_CONTINUE                                           281                            /* 'continue' */
 
4810
#define DUK_STRIDX_DEBUGGER                                           282                            /* 'debugger' */
 
4811
#define DUK_STRIDX_DEFAULT                                            283                            /* 'default' */
 
4812
#define DUK_STRIDX_DELETE                                             284                            /* 'delete' */
 
4813
#define DUK_STRIDX_DO                                                 285                            /* 'do' */
 
4814
#define DUK_STRIDX_ELSE                                               286                            /* 'else' */
 
4815
#define DUK_STRIDX_FINALLY                                            287                            /* 'finally' */
 
4816
#define DUK_STRIDX_FOR                                                288                            /* 'for' */
 
4817
#define DUK_STRIDX_LC_FUNCTION                                        289                            /* 'function' */
 
4818
#define DUK_STRIDX_IF                                                 290                            /* 'if' */
 
4819
#define DUK_STRIDX_IN                                                 291                            /* 'in' */
 
4820
#define DUK_STRIDX_INSTANCEOF                                         292                            /* 'instanceof' */
 
4821
#define DUK_STRIDX_NEW                                                293                            /* 'new' */
 
4822
#define DUK_STRIDX_RETURN                                             294                            /* 'return' */
 
4823
#define DUK_STRIDX_SWITCH                                             295                            /* 'switch' */
 
4824
#define DUK_STRIDX_THIS                                               296                            /* 'this' */
 
4825
#define DUK_STRIDX_THROW                                              297                            /* 'throw' */
 
4826
#define DUK_STRIDX_TRY                                                298                            /* 'try' */
 
4827
#define DUK_STRIDX_TYPEOF                                             299                            /* 'typeof' */
 
4828
#define DUK_STRIDX_VAR                                                300                            /* 'var' */
 
4829
#define DUK_STRIDX_VOID                                               301                            /* 'void' */
 
4830
#define DUK_STRIDX_WHILE                                              302                            /* 'while' */
 
4831
#define DUK_STRIDX_WITH                                               303                            /* 'with' */
 
4832
#define DUK_STRIDX_CLASS                                              304                            /* 'class' */
 
4833
#define DUK_STRIDX_CONST                                              305                            /* 'const' */
 
4834
#define DUK_STRIDX_ENUM                                               306                            /* 'enum' */
 
4835
#define DUK_STRIDX_EXPORT                                             307                            /* 'export' */
 
4836
#define DUK_STRIDX_EXTENDS                                            308                            /* 'extends' */
 
4837
#define DUK_STRIDX_IMPORT                                             309                            /* 'import' */
 
4838
#define DUK_STRIDX_SUPER                                              310                            /* 'super' */
 
4839
#define DUK_STRIDX_NULL                                               311                            /* 'null' */
 
4840
#define DUK_STRIDX_TRUE                                               312                            /* 'true' */
 
4841
#define DUK_STRIDX_FALSE                                              313                            /* 'false' */
 
4842
#define DUK_STRIDX_IMPLEMENTS                                         314                            /* 'implements' */
 
4843
#define DUK_STRIDX_INTERFACE                                          315                            /* 'interface' */
 
4844
#define DUK_STRIDX_LET                                                316                            /* 'let' */
 
4845
#define DUK_STRIDX_PACKAGE                                            317                            /* 'package' */
 
4846
#define DUK_STRIDX_PRIVATE                                            318                            /* 'private' */
 
4847
#define DUK_STRIDX_PROTECTED                                          319                            /* 'protected' */
 
4848
#define DUK_STRIDX_PUBLIC                                             320                            /* 'public' */
 
4849
#define DUK_STRIDX_STATIC                                             321                            /* 'static' */
 
4850
#define DUK_STRIDX_YIELD                                              322                            /* 'yield' */
 
4851
 
 
4852
#define DUK_HEAP_STRING_UC_LOGGER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_LOGGER)
 
4853
#define DUK_HTHREAD_STRING_UC_LOGGER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_LOGGER)
 
4854
#define DUK_HEAP_STRING_UC_THREAD(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
 
4855
#define DUK_HTHREAD_STRING_UC_THREAD(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
 
4856
#define DUK_HEAP_STRING_UC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
 
4857
#define DUK_HTHREAD_STRING_UC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
 
4858
#define DUK_HEAP_STRING_UC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
 
4859
#define DUK_HTHREAD_STRING_UC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
 
4860
#define DUK_HEAP_STRING_DEC_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
 
4861
#define DUK_HTHREAD_STRING_DEC_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
 
4862
#define DUK_HEAP_STRING_OBJ_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
 
4863
#define DUK_HTHREAD_STRING_OBJ_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
 
4864
#define DUK_HEAP_STRING_EMPTY_STRING(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
 
4865
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
 
4866
#define DUK_HEAP_STRING_GLOBAL(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
 
4867
#define DUK_HTHREAD_STRING_GLOBAL(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
 
4868
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
 
4869
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
 
4870
#define DUK_HEAP_STRING_JSON(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
 
4871
#define DUK_HTHREAD_STRING_JSON(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
 
4872
#define DUK_HEAP_STRING_MATH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
 
4873
#define DUK_HTHREAD_STRING_MATH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
 
4874
#define DUK_HEAP_STRING_UC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
 
4875
#define DUK_HTHREAD_STRING_UC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
 
4876
#define DUK_HEAP_STRING_REG_EXP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
 
4877
#define DUK_HTHREAD_STRING_REG_EXP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
 
4878
#define DUK_HEAP_STRING_DATE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
 
4879
#define DUK_HTHREAD_STRING_DATE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
 
4880
#define DUK_HEAP_STRING_UC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
 
4881
#define DUK_HTHREAD_STRING_UC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
 
4882
#define DUK_HEAP_STRING_UC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
 
4883
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
 
4884
#define DUK_HEAP_STRING_UC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
 
4885
#define DUK_HTHREAD_STRING_UC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
 
4886
#define DUK_HEAP_STRING_ARRAY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
 
4887
#define DUK_HTHREAD_STRING_ARRAY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
 
4888
#define DUK_HEAP_STRING_UC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
 
4889
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
 
4890
#define DUK_HEAP_STRING_UC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
 
4891
#define DUK_HTHREAD_STRING_UC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
 
4892
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
4893
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
 
4894
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
4895
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
 
4896
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
 
4897
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
 
4898
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
 
4899
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
 
4900
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
 
4901
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
 
4902
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
4903
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
 
4904
#define DUK_HEAP_STRING_TO_LOG_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
 
4905
#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
 
4906
#define DUK_HEAP_STRING_CLOG(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
 
4907
#define DUK_HTHREAD_STRING_CLOG(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
 
4908
#define DUK_HEAP_STRING_LC_L(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
 
4909
#define DUK_HTHREAD_STRING_LC_L(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
 
4910
#define DUK_HEAP_STRING_LC_N(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
 
4911
#define DUK_HTHREAD_STRING_LC_N(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
 
4912
#define DUK_HEAP_STRING_LC_FATAL(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
 
4913
#define DUK_HTHREAD_STRING_LC_FATAL(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
 
4914
#define DUK_HEAP_STRING_LC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
 
4915
#define DUK_HTHREAD_STRING_LC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
 
4916
#define DUK_HEAP_STRING_LC_WARN(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
 
4917
#define DUK_HTHREAD_STRING_LC_WARN(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
 
4918
#define DUK_HEAP_STRING_LC_DEBUG(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
 
4919
#define DUK_HTHREAD_STRING_LC_DEBUG(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
 
4920
#define DUK_HEAP_STRING_LC_TRACE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
 
4921
#define DUK_HTHREAD_STRING_LC_TRACE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
 
4922
#define DUK_HEAP_STRING_RAW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
 
4923
#define DUK_HTHREAD_STRING_RAW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
 
4924
#define DUK_HEAP_STRING_FMT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
 
4925
#define DUK_HTHREAD_STRING_FMT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
 
4926
#define DUK_HEAP_STRING_CURRENT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CURRENT)
 
4927
#define DUK_HTHREAD_STRING_CURRENT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CURRENT)
 
4928
#define DUK_HEAP_STRING_RESUME(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
 
4929
#define DUK_HTHREAD_STRING_RESUME(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
 
4930
#define DUK_HEAP_STRING_COMPACT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPACT)
 
4931
#define DUK_HTHREAD_STRING_COMPACT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPACT)
 
4932
#define DUK_HEAP_STRING_JSONC(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONC)
 
4933
#define DUK_HTHREAD_STRING_JSONC(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONC)
 
4934
#define DUK_HEAP_STRING_JSONX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSONX)
 
4935
#define DUK_HTHREAD_STRING_JSONX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSONX)
 
4936
#define DUK_HEAP_STRING_BASE64(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
 
4937
#define DUK_HTHREAD_STRING_BASE64(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
 
4938
#define DUK_HEAP_STRING_HEX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
 
4939
#define DUK_HTHREAD_STRING_HEX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
 
4940
#define DUK_HEAP_STRING_DEC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC)
 
4941
#define DUK_HTHREAD_STRING_DEC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC)
 
4942
#define DUK_HEAP_STRING_ENC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENC)
 
4943
#define DUK_HTHREAD_STRING_ENC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENC)
 
4944
#define DUK_HEAP_STRING_FIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FIN)
 
4945
#define DUK_HTHREAD_STRING_FIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FIN)
 
4946
#define DUK_HEAP_STRING_GC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GC)
 
4947
#define DUK_HTHREAD_STRING_GC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GC)
 
4948
#define DUK_HEAP_STRING_ACT(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACT)
 
4949
#define DUK_HTHREAD_STRING_ACT(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACT)
 
4950
#define DUK_HEAP_STRING_LINE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE)
 
4951
#define DUK_HTHREAD_STRING_LINE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE)
 
4952
#define DUK_HEAP_STRING_LC_INFO(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
 
4953
#define DUK_HTHREAD_STRING_LC_INFO(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
 
4954
#define DUK_HEAP_STRING_VERSION(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VERSION)
 
4955
#define DUK_HTHREAD_STRING_VERSION(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VERSION)
 
4956
#define DUK_HEAP_STRING_ENV(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
 
4957
#define DUK_HTHREAD_STRING_ENV(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
 
4958
#define DUK_HEAP_STRING_ERRTHROW(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRTHROW)
 
4959
#define DUK_HTHREAD_STRING_ERRTHROW(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRTHROW)
 
4960
#define DUK_HEAP_STRING_ERRCREATE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERRCREATE)
 
4961
#define DUK_HTHREAD_STRING_ERRCREATE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERRCREATE)
 
4962
#define DUK_HEAP_STRING_COMPILE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
 
4963
#define DUK_HTHREAD_STRING_COMPILE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
 
4964
#define DUK_HEAP_STRING_INT_REGBASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
 
4965
#define DUK_HTHREAD_STRING_INT_REGBASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
 
4966
#define DUK_HEAP_STRING_INT_THREAD(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
 
4967
#define DUK_HTHREAD_STRING_INT_THREAD(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
 
4968
#define DUK_HEAP_STRING_INT_FINALIZER(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
 
4969
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
 
4970
#define DUK_HEAP_STRING_INT_CALLEE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
 
4971
#define DUK_HTHREAD_STRING_INT_CALLEE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
 
4972
#define DUK_HEAP_STRING_INT_MAP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
 
4973
#define DUK_HTHREAD_STRING_INT_MAP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
 
4974
#define DUK_HEAP_STRING_INT_ARGS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
 
4975
#define DUK_HTHREAD_STRING_INT_ARGS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
 
4976
#define DUK_HEAP_STRING_INT_THIS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
 
4977
#define DUK_HTHREAD_STRING_INT_THIS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
 
4978
#define DUK_HEAP_STRING_INT_PC2LINE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
 
4979
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
 
4980
#define DUK_HEAP_STRING_INT_SOURCE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
 
4981
#define DUK_HTHREAD_STRING_INT_SOURCE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
 
4982
#define DUK_HEAP_STRING_INT_VARENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
 
4983
#define DUK_HTHREAD_STRING_INT_VARENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
 
4984
#define DUK_HEAP_STRING_INT_LEXENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
 
4985
#define DUK_HTHREAD_STRING_INT_LEXENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
 
4986
#define DUK_HEAP_STRING_INT_VARMAP(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
 
4987
#define DUK_HTHREAD_STRING_INT_VARMAP(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
 
4988
#define DUK_HEAP_STRING_INT_FORMALS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
 
4989
#define DUK_HTHREAD_STRING_INT_FORMALS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
 
4990
#define DUK_HEAP_STRING_INT_BYTECODE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
 
4991
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
 
4992
#define DUK_HEAP_STRING_INT_NEXT(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
 
4993
#define DUK_HTHREAD_STRING_INT_NEXT(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
 
4994
#define DUK_HEAP_STRING_INT_TARGET(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
 
4995
#define DUK_HTHREAD_STRING_INT_TARGET(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
 
4996
#define DUK_HEAP_STRING_INT_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
 
4997
#define DUK_HTHREAD_STRING_INT_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
 
4998
#define DUK_HEAP_STRING_LC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
 
4999
#define DUK_HTHREAD_STRING_LC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
 
5000
#define DUK_HEAP_STRING_LC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
 
5001
#define DUK_HTHREAD_STRING_LC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
 
5002
#define DUK_HEAP_STRING_TRACEDATA(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRACEDATA)
 
5003
#define DUK_HTHREAD_STRING_TRACEDATA(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRACEDATA)
 
5004
#define DUK_HEAP_STRING_LINE_NUMBER(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
 
5005
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
 
5006
#define DUK_HEAP_STRING_FILE_NAME(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
 
5007
#define DUK_HTHREAD_STRING_FILE_NAME(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
 
5008
#define DUK_HEAP_STRING_PC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
 
5009
#define DUK_HTHREAD_STRING_PC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
 
5010
#define DUK_HEAP_STRING_STACK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
 
5011
#define DUK_HTHREAD_STRING_STACK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
 
5012
#define DUK_HEAP_STRING_THROW_TYPE_ERROR(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW_TYPE_ERROR)
 
5013
#define DUK_HTHREAD_STRING_THROW_TYPE_ERROR(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW_TYPE_ERROR)
 
5014
#define DUK_HEAP_STRING_DUKTAPE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DUKTAPE)
 
5015
#define DUK_HTHREAD_STRING_DUKTAPE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DUKTAPE)
 
5016
#define DUK_HEAP_STRING_CALLEE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
 
5017
#define DUK_HTHREAD_STRING_CALLEE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
 
5018
#define DUK_HEAP_STRING_INVALID_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
 
5019
#define DUK_HTHREAD_STRING_INVALID_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
 
5020
#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
5021
#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
 
5022
#define DUK_HEAP_STRING_NEWLINE_TAB(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_TAB)
 
5023
#define DUK_HTHREAD_STRING_NEWLINE_TAB(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_TAB)
 
5024
#define DUK_HEAP_STRING_SPACE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
 
5025
#define DUK_HTHREAD_STRING_SPACE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
 
5026
#define DUK_HEAP_STRING_COMMA(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
 
5027
#define DUK_HTHREAD_STRING_COMMA(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
 
5028
#define DUK_HEAP_STRING_MINUS_ZERO(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
 
5029
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
 
5030
#define DUK_HEAP_STRING_PLUS_ZERO(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_ZERO)
 
5031
#define DUK_HTHREAD_STRING_PLUS_ZERO(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_ZERO)
 
5032
#define DUK_HEAP_STRING_ZERO(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ZERO)
 
5033
#define DUK_HTHREAD_STRING_ZERO(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ZERO)
 
5034
#define DUK_HEAP_STRING_MINUS_INFINITY(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
 
5035
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
 
5036
#define DUK_HEAP_STRING_PLUS_INFINITY(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PLUS_INFINITY)
 
5037
#define DUK_HTHREAD_STRING_PLUS_INFINITY(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PLUS_INFINITY)
 
5038
#define DUK_HEAP_STRING_INFINITY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
 
5039
#define DUK_HTHREAD_STRING_INFINITY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
 
5040
#define DUK_HEAP_STRING_LC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
 
5041
#define DUK_HTHREAD_STRING_LC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
 
5042
#define DUK_HEAP_STRING_LC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
 
5043
#define DUK_HTHREAD_STRING_LC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
 
5044
#define DUK_HEAP_STRING_LC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
 
5045
#define DUK_HTHREAD_STRING_LC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
 
5046
#define DUK_HEAP_STRING_LC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
 
5047
#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
 
5048
#define DUK_HEAP_STRING_UNDEFINED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNDEFINED)
 
5049
#define DUK_HTHREAD_STRING_UNDEFINED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNDEFINED)
 
5050
#define DUK_HEAP_STRING_STRINGIFY(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STRINGIFY)
 
5051
#define DUK_HTHREAD_STRING_STRINGIFY(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STRINGIFY)
 
5052
#define DUK_HEAP_STRING_TAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TAN)
 
5053
#define DUK_HTHREAD_STRING_TAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TAN)
 
5054
#define DUK_HEAP_STRING_SQRT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT)
 
5055
#define DUK_HTHREAD_STRING_SQRT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT)
 
5056
#define DUK_HEAP_STRING_SIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SIN)
 
5057
#define DUK_HTHREAD_STRING_SIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SIN)
 
5058
#define DUK_HEAP_STRING_ROUND(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ROUND)
 
5059
#define DUK_HTHREAD_STRING_ROUND(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ROUND)
 
5060
#define DUK_HEAP_STRING_RANDOM(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANDOM)
 
5061
#define DUK_HTHREAD_STRING_RANDOM(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANDOM)
 
5062
#define DUK_HEAP_STRING_POW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POW)
 
5063
#define DUK_HTHREAD_STRING_POW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POW)
 
5064
#define DUK_HEAP_STRING_MIN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN)
 
5065
#define DUK_HTHREAD_STRING_MIN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN)
 
5066
#define DUK_HEAP_STRING_MAX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX)
 
5067
#define DUK_HTHREAD_STRING_MAX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX)
 
5068
#define DUK_HEAP_STRING_LOG(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG)
 
5069
#define DUK_HTHREAD_STRING_LOG(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG)
 
5070
#define DUK_HEAP_STRING_FLOOR(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOOR)
 
5071
#define DUK_HTHREAD_STRING_FLOOR(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOOR)
 
5072
#define DUK_HEAP_STRING_EXP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXP)
 
5073
#define DUK_HTHREAD_STRING_EXP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXP)
 
5074
#define DUK_HEAP_STRING_COS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COS)
 
5075
#define DUK_HTHREAD_STRING_COS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COS)
 
5076
#define DUK_HEAP_STRING_CEIL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CEIL)
 
5077
#define DUK_HTHREAD_STRING_CEIL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CEIL)
 
5078
#define DUK_HEAP_STRING_ATAN2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN2)
 
5079
#define DUK_HTHREAD_STRING_ATAN2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN2)
 
5080
#define DUK_HEAP_STRING_ATAN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ATAN)
 
5081
#define DUK_HTHREAD_STRING_ATAN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ATAN)
 
5082
#define DUK_HEAP_STRING_ASIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ASIN)
 
5083
#define DUK_HTHREAD_STRING_ASIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ASIN)
 
5084
#define DUK_HEAP_STRING_ACOS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ACOS)
 
5085
#define DUK_HTHREAD_STRING_ACOS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ACOS)
 
5086
#define DUK_HEAP_STRING_ABS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ABS)
 
5087
#define DUK_HTHREAD_STRING_ABS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ABS)
 
5088
#define DUK_HEAP_STRING_SQRT2(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT2)
 
5089
#define DUK_HTHREAD_STRING_SQRT2(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT2)
 
5090
#define DUK_HEAP_STRING_SQRT1_2(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SQRT1_2)
 
5091
#define DUK_HTHREAD_STRING_SQRT1_2(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SQRT1_2)
 
5092
#define DUK_HEAP_STRING_PI(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PI)
 
5093
#define DUK_HTHREAD_STRING_PI(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PI)
 
5094
#define DUK_HEAP_STRING_LOG10E(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG10E)
 
5095
#define DUK_HTHREAD_STRING_LOG10E(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG10E)
 
5096
#define DUK_HEAP_STRING_LOG2E(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOG2E)
 
5097
#define DUK_HTHREAD_STRING_LOG2E(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOG2E)
 
5098
#define DUK_HEAP_STRING_LN2(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN2)
 
5099
#define DUK_HTHREAD_STRING_LN2(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN2)
 
5100
#define DUK_HEAP_STRING_LN10(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LN10)
 
5101
#define DUK_HTHREAD_STRING_LN10(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LN10)
 
5102
#define DUK_HEAP_STRING_E(heap)                                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_E)
 
5103
#define DUK_HTHREAD_STRING_E(thr)                                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_E)
 
5104
#define DUK_HEAP_STRING_MESSAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
 
5105
#define DUK_HTHREAD_STRING_MESSAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
 
5106
#define DUK_HEAP_STRING_NAME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
 
5107
#define DUK_HTHREAD_STRING_NAME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
 
5108
#define DUK_HEAP_STRING_INPUT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
 
5109
#define DUK_HTHREAD_STRING_INPUT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
 
5110
#define DUK_HEAP_STRING_INDEX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
 
5111
#define DUK_HTHREAD_STRING_INDEX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
 
5112
#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
5113
#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
 
5114
#define DUK_HEAP_STRING_LAST_INDEX(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
 
5115
#define DUK_HTHREAD_STRING_LAST_INDEX(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
 
5116
#define DUK_HEAP_STRING_MULTILINE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
 
5117
#define DUK_HTHREAD_STRING_MULTILINE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
 
5118
#define DUK_HEAP_STRING_IGNORE_CASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
 
5119
#define DUK_HTHREAD_STRING_IGNORE_CASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
 
5120
#define DUK_HEAP_STRING_SOURCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
 
5121
#define DUK_HTHREAD_STRING_SOURCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
 
5122
#define DUK_HEAP_STRING_TEST(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TEST)
 
5123
#define DUK_HTHREAD_STRING_TEST(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TEST)
 
5124
#define DUK_HEAP_STRING_EXEC(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXEC)
 
5125
#define DUK_HTHREAD_STRING_EXEC(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXEC)
 
5126
#define DUK_HEAP_STRING_TO_GMT_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
 
5127
#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
 
5128
#define DUK_HEAP_STRING_SET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_YEAR)
 
5129
#define DUK_HTHREAD_STRING_SET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_YEAR)
 
5130
#define DUK_HEAP_STRING_GET_YEAR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_YEAR)
 
5131
#define DUK_HTHREAD_STRING_GET_YEAR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_YEAR)
 
5132
#define DUK_HEAP_STRING_TO_JSON(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
 
5133
#define DUK_HTHREAD_STRING_TO_JSON(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
 
5134
#define DUK_HEAP_STRING_TO_ISO_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
 
5135
#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
 
5136
#define DUK_HEAP_STRING_TO_UTC_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
 
5137
#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
 
5138
#define DUK_HEAP_STRING_SET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
5139
#define DUK_HTHREAD_STRING_SET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_FULL_YEAR)
 
5140
#define DUK_HEAP_STRING_SET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_FULL_YEAR)
 
5141
#define DUK_HTHREAD_STRING_SET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_FULL_YEAR)
 
5142
#define DUK_HEAP_STRING_SET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MONTH)
 
5143
#define DUK_HTHREAD_STRING_SET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MONTH)
 
5144
#define DUK_HEAP_STRING_SET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MONTH)
 
5145
#define DUK_HTHREAD_STRING_SET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MONTH)
 
5146
#define DUK_HEAP_STRING_SET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_DATE)
 
5147
#define DUK_HTHREAD_STRING_SET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_DATE)
 
5148
#define DUK_HEAP_STRING_SET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_DATE)
 
5149
#define DUK_HTHREAD_STRING_SET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_DATE)
 
5150
#define DUK_HEAP_STRING_SET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_HOURS)
 
5151
#define DUK_HTHREAD_STRING_SET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_HOURS)
 
5152
#define DUK_HEAP_STRING_SET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_HOURS)
 
5153
#define DUK_HTHREAD_STRING_SET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_HOURS)
 
5154
#define DUK_HEAP_STRING_SET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MINUTES)
 
5155
#define DUK_HTHREAD_STRING_SET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MINUTES)
 
5156
#define DUK_HEAP_STRING_SET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MINUTES)
 
5157
#define DUK_HTHREAD_STRING_SET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MINUTES)
 
5158
#define DUK_HEAP_STRING_SET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_SECONDS)
 
5159
#define DUK_HTHREAD_STRING_SET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_SECONDS)
 
5160
#define DUK_HEAP_STRING_SET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_SECONDS)
 
5161
#define DUK_HTHREAD_STRING_SET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_SECONDS)
 
5162
#define DUK_HEAP_STRING_SET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
5163
#define DUK_HTHREAD_STRING_SET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_UTC_MILLISECONDS)
 
5164
#define DUK_HEAP_STRING_SET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_MILLISECONDS)
 
5165
#define DUK_HTHREAD_STRING_SET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_MILLISECONDS)
 
5166
#define DUK_HEAP_STRING_SET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_TIME)
 
5167
#define DUK_HTHREAD_STRING_SET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_TIME)
 
5168
#define DUK_HEAP_STRING_GET_TIMEZONE_OFFSET(heap)                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
5169
#define DUK_HTHREAD_STRING_GET_TIMEZONE_OFFSET(thr)                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIMEZONE_OFFSET)
 
5170
#define DUK_HEAP_STRING_GET_UTC_MILLISECONDS(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
5171
#define DUK_HTHREAD_STRING_GET_UTC_MILLISECONDS(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MILLISECONDS)
 
5172
#define DUK_HEAP_STRING_GET_MILLISECONDS(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MILLISECONDS)
 
5173
#define DUK_HTHREAD_STRING_GET_MILLISECONDS(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MILLISECONDS)
 
5174
#define DUK_HEAP_STRING_GET_UTC_SECONDS(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_SECONDS)
 
5175
#define DUK_HTHREAD_STRING_GET_UTC_SECONDS(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_SECONDS)
 
5176
#define DUK_HEAP_STRING_GET_SECONDS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_SECONDS)
 
5177
#define DUK_HTHREAD_STRING_GET_SECONDS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_SECONDS)
 
5178
#define DUK_HEAP_STRING_GET_UTC_MINUTES(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MINUTES)
 
5179
#define DUK_HTHREAD_STRING_GET_UTC_MINUTES(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MINUTES)
 
5180
#define DUK_HEAP_STRING_GET_MINUTES(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MINUTES)
 
5181
#define DUK_HTHREAD_STRING_GET_MINUTES(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MINUTES)
 
5182
#define DUK_HEAP_STRING_GET_UTC_HOURS(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_HOURS)
 
5183
#define DUK_HTHREAD_STRING_GET_UTC_HOURS(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_HOURS)
 
5184
#define DUK_HEAP_STRING_GET_HOURS(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_HOURS)
 
5185
#define DUK_HTHREAD_STRING_GET_HOURS(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_HOURS)
 
5186
#define DUK_HEAP_STRING_GET_UTC_DAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DAY)
 
5187
#define DUK_HTHREAD_STRING_GET_UTC_DAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DAY)
 
5188
#define DUK_HEAP_STRING_GET_DAY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DAY)
 
5189
#define DUK_HTHREAD_STRING_GET_DAY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DAY)
 
5190
#define DUK_HEAP_STRING_GET_UTC_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_DATE)
 
5191
#define DUK_HTHREAD_STRING_GET_UTC_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_DATE)
 
5192
#define DUK_HEAP_STRING_GET_DATE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_DATE)
 
5193
#define DUK_HTHREAD_STRING_GET_DATE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_DATE)
 
5194
#define DUK_HEAP_STRING_GET_UTC_MONTH(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_MONTH)
 
5195
#define DUK_HTHREAD_STRING_GET_UTC_MONTH(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_MONTH)
 
5196
#define DUK_HEAP_STRING_GET_MONTH(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_MONTH)
 
5197
#define DUK_HTHREAD_STRING_GET_MONTH(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_MONTH)
 
5198
#define DUK_HEAP_STRING_GET_UTC_FULL_YEAR(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
5199
#define DUK_HTHREAD_STRING_GET_UTC_FULL_YEAR(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_UTC_FULL_YEAR)
 
5200
#define DUK_HEAP_STRING_GET_FULL_YEAR(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_FULL_YEAR)
 
5201
#define DUK_HTHREAD_STRING_GET_FULL_YEAR(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_FULL_YEAR)
 
5202
#define DUK_HEAP_STRING_GET_TIME(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_TIME)
 
5203
#define DUK_HTHREAD_STRING_GET_TIME(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_TIME)
 
5204
#define DUK_HEAP_STRING_TO_LOCALE_TIME_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
5205
#define DUK_HTHREAD_STRING_TO_LOCALE_TIME_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_TIME_STRING)
 
5206
#define DUK_HEAP_STRING_TO_LOCALE_DATE_STRING(heap)                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
5207
#define DUK_HTHREAD_STRING_TO_LOCALE_DATE_STRING(thr)                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_DATE_STRING)
 
5208
#define DUK_HEAP_STRING_TO_TIME_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_TIME_STRING)
 
5209
#define DUK_HTHREAD_STRING_TO_TIME_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_TIME_STRING)
 
5210
#define DUK_HEAP_STRING_TO_DATE_STRING(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_DATE_STRING)
 
5211
#define DUK_HTHREAD_STRING_TO_DATE_STRING(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_DATE_STRING)
 
5212
#define DUK_HEAP_STRING_NOW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NOW)
 
5213
#define DUK_HTHREAD_STRING_NOW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NOW)
 
5214
#define DUK_HEAP_STRING_UTC(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UTC)
 
5215
#define DUK_HTHREAD_STRING_UTC(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UTC)
 
5216
#define DUK_HEAP_STRING_PARSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE)
 
5217
#define DUK_HTHREAD_STRING_PARSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE)
 
5218
#define DUK_HEAP_STRING_TO_PRECISION(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_PRECISION)
 
5219
#define DUK_HTHREAD_STRING_TO_PRECISION(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_PRECISION)
 
5220
#define DUK_HEAP_STRING_TO_EXPONENTIAL(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_EXPONENTIAL)
 
5221
#define DUK_HTHREAD_STRING_TO_EXPONENTIAL(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_EXPONENTIAL)
 
5222
#define DUK_HEAP_STRING_TO_FIXED(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_FIXED)
 
5223
#define DUK_HTHREAD_STRING_TO_FIXED(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_FIXED)
 
5224
#define DUK_HEAP_STRING_POSITIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POSITIVE_INFINITY)
 
5225
#define DUK_HTHREAD_STRING_POSITIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POSITIVE_INFINITY)
 
5226
#define DUK_HEAP_STRING_NEGATIVE_INFINITY(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEGATIVE_INFINITY)
 
5227
#define DUK_HTHREAD_STRING_NEGATIVE_INFINITY(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEGATIVE_INFINITY)
 
5228
#define DUK_HEAP_STRING_NAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
 
5229
#define DUK_HTHREAD_STRING_NAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
 
5230
#define DUK_HEAP_STRING_MIN_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MIN_VALUE)
 
5231
#define DUK_HTHREAD_STRING_MIN_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MIN_VALUE)
 
5232
#define DUK_HEAP_STRING_MAX_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAX_VALUE)
 
5233
#define DUK_HTHREAD_STRING_MAX_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAX_VALUE)
 
5234
#define DUK_HEAP_STRING_SUBSTR(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTR)
 
5235
#define DUK_HTHREAD_STRING_SUBSTR(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTR)
 
5236
#define DUK_HEAP_STRING_TRIM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRIM)
 
5237
#define DUK_HTHREAD_STRING_TRIM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRIM)
 
5238
#define DUK_HEAP_STRING_TO_LOCALE_UPPER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
5239
#define DUK_HTHREAD_STRING_TO_LOCALE_UPPER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_UPPER_CASE)
 
5240
#define DUK_HEAP_STRING_TO_UPPER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UPPER_CASE)
 
5241
#define DUK_HTHREAD_STRING_TO_UPPER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UPPER_CASE)
 
5242
#define DUK_HEAP_STRING_TO_LOCALE_LOWER_CASE(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
5243
#define DUK_HTHREAD_STRING_TO_LOCALE_LOWER_CASE(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_LOWER_CASE)
 
5244
#define DUK_HEAP_STRING_TO_LOWER_CASE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOWER_CASE)
 
5245
#define DUK_HTHREAD_STRING_TO_LOWER_CASE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOWER_CASE)
 
5246
#define DUK_HEAP_STRING_SUBSTRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUBSTRING)
 
5247
#define DUK_HTHREAD_STRING_SUBSTRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUBSTRING)
 
5248
#define DUK_HEAP_STRING_SPLIT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLIT)
 
5249
#define DUK_HTHREAD_STRING_SPLIT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLIT)
 
5250
#define DUK_HEAP_STRING_SEARCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEARCH)
 
5251
#define DUK_HTHREAD_STRING_SEARCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEARCH)
 
5252
#define DUK_HEAP_STRING_REPLACE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REPLACE)
 
5253
#define DUK_HTHREAD_STRING_REPLACE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REPLACE)
 
5254
#define DUK_HEAP_STRING_MATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATCH)
 
5255
#define DUK_HTHREAD_STRING_MATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATCH)
 
5256
#define DUK_HEAP_STRING_LOCALE_COMPARE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LOCALE_COMPARE)
 
5257
#define DUK_HTHREAD_STRING_LOCALE_COMPARE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LOCALE_COMPARE)
 
5258
#define DUK_HEAP_STRING_CHAR_CODE_AT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_CODE_AT)
 
5259
#define DUK_HTHREAD_STRING_CHAR_CODE_AT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_CODE_AT)
 
5260
#define DUK_HEAP_STRING_CHAR_AT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CHAR_AT)
 
5261
#define DUK_HTHREAD_STRING_CHAR_AT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CHAR_AT)
 
5262
#define DUK_HEAP_STRING_FROM_CHAR_CODE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FROM_CHAR_CODE)
 
5263
#define DUK_HTHREAD_STRING_FROM_CHAR_CODE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FROM_CHAR_CODE)
 
5264
#define DUK_HEAP_STRING_REDUCE_RIGHT(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE_RIGHT)
 
5265
#define DUK_HTHREAD_STRING_REDUCE_RIGHT(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE_RIGHT)
 
5266
#define DUK_HEAP_STRING_REDUCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REDUCE)
 
5267
#define DUK_HTHREAD_STRING_REDUCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REDUCE)
 
5268
#define DUK_HEAP_STRING_FILTER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILTER)
 
5269
#define DUK_HTHREAD_STRING_FILTER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILTER)
 
5270
#define DUK_HEAP_STRING_MAP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MAP)
 
5271
#define DUK_HTHREAD_STRING_MAP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MAP)
 
5272
#define DUK_HEAP_STRING_FOR_EACH(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR_EACH)
 
5273
#define DUK_HTHREAD_STRING_FOR_EACH(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR_EACH)
 
5274
#define DUK_HEAP_STRING_SOME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOME)
 
5275
#define DUK_HTHREAD_STRING_SOME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOME)
 
5276
#define DUK_HEAP_STRING_EVERY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVERY)
 
5277
#define DUK_HTHREAD_STRING_EVERY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVERY)
 
5278
#define DUK_HEAP_STRING_LAST_INDEX_OF(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX_OF)
 
5279
#define DUK_HTHREAD_STRING_LAST_INDEX_OF(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX_OF)
 
5280
#define DUK_HEAP_STRING_INDEX_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX_OF)
 
5281
#define DUK_HTHREAD_STRING_INDEX_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX_OF)
 
5282
#define DUK_HEAP_STRING_UNSHIFT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNSHIFT)
 
5283
#define DUK_HTHREAD_STRING_UNSHIFT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNSHIFT)
 
5284
#define DUK_HEAP_STRING_SPLICE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPLICE)
 
5285
#define DUK_HTHREAD_STRING_SPLICE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPLICE)
 
5286
#define DUK_HEAP_STRING_SORT(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SORT)
 
5287
#define DUK_HTHREAD_STRING_SORT(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SORT)
 
5288
#define DUK_HEAP_STRING_SLICE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SLICE)
 
5289
#define DUK_HTHREAD_STRING_SLICE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SLICE)
 
5290
#define DUK_HEAP_STRING_SHIFT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SHIFT)
 
5291
#define DUK_HTHREAD_STRING_SHIFT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SHIFT)
 
5292
#define DUK_HEAP_STRING_REVERSE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REVERSE)
 
5293
#define DUK_HTHREAD_STRING_REVERSE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REVERSE)
 
5294
#define DUK_HEAP_STRING_PUSH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUSH)
 
5295
#define DUK_HTHREAD_STRING_PUSH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUSH)
 
5296
#define DUK_HEAP_STRING_POP(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_POP)
 
5297
#define DUK_HTHREAD_STRING_POP(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_POP)
 
5298
#define DUK_HEAP_STRING_JOIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
 
5299
#define DUK_HTHREAD_STRING_JOIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
 
5300
#define DUK_HEAP_STRING_CONCAT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONCAT)
 
5301
#define DUK_HTHREAD_STRING_CONCAT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONCAT)
 
5302
#define DUK_HEAP_STRING_IS_ARRAY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_ARRAY)
 
5303
#define DUK_HTHREAD_STRING_IS_ARRAY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_ARRAY)
 
5304
#define DUK_HEAP_STRING_LC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
 
5305
#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
 
5306
#define DUK_HEAP_STRING_CALLER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
 
5307
#define DUK_HTHREAD_STRING_CALLER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
 
5308
#define DUK_HEAP_STRING_BIND(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BIND)
 
5309
#define DUK_HTHREAD_STRING_BIND(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BIND)
 
5310
#define DUK_HEAP_STRING_CALL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALL)
 
5311
#define DUK_HTHREAD_STRING_CALL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALL)
 
5312
#define DUK_HEAP_STRING_APPLY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
 
5313
#define DUK_HTHREAD_STRING_APPLY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
 
5314
#define DUK_HEAP_STRING_PROPERTY_IS_ENUMERABLE(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
5315
#define DUK_HTHREAD_STRING_PROPERTY_IS_ENUMERABLE(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROPERTY_IS_ENUMERABLE)
 
5316
#define DUK_HEAP_STRING_IS_PROTOTYPE_OF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_PROTOTYPE_OF)
 
5317
#define DUK_HTHREAD_STRING_IS_PROTOTYPE_OF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_PROTOTYPE_OF)
 
5318
#define DUK_HEAP_STRING_HAS_OWN_PROPERTY(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS_OWN_PROPERTY)
 
5319
#define DUK_HTHREAD_STRING_HAS_OWN_PROPERTY(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS_OWN_PROPERTY)
 
5320
#define DUK_HEAP_STRING_VALUE_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
 
5321
#define DUK_HTHREAD_STRING_VALUE_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
 
5322
#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
 
5323
#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
 
5324
#define DUK_HEAP_STRING_TO_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
 
5325
#define DUK_HTHREAD_STRING_TO_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
 
5326
#define DUK_HEAP_STRING_CONSTRUCTOR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
 
5327
#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
 
5328
#define DUK_HEAP_STRING_SET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
 
5329
#define DUK_HTHREAD_STRING_SET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
 
5330
#define DUK_HEAP_STRING_GET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
 
5331
#define DUK_HTHREAD_STRING_GET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
 
5332
#define DUK_HEAP_STRING_ENUMERABLE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
 
5333
#define DUK_HTHREAD_STRING_ENUMERABLE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
 
5334
#define DUK_HEAP_STRING_CONFIGURABLE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
 
5335
#define DUK_HTHREAD_STRING_CONFIGURABLE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
 
5336
#define DUK_HEAP_STRING_WRITABLE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
 
5337
#define DUK_HTHREAD_STRING_WRITABLE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
 
5338
#define DUK_HEAP_STRING_VALUE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
 
5339
#define DUK_HTHREAD_STRING_VALUE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
 
5340
#define DUK_HEAP_STRING_KEYS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_KEYS)
 
5341
#define DUK_HTHREAD_STRING_KEYS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_KEYS)
 
5342
#define DUK_HEAP_STRING_IS_EXTENSIBLE(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_EXTENSIBLE)
 
5343
#define DUK_HTHREAD_STRING_IS_EXTENSIBLE(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_EXTENSIBLE)
 
5344
#define DUK_HEAP_STRING_IS_FROZEN(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FROZEN)
 
5345
#define DUK_HTHREAD_STRING_IS_FROZEN(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FROZEN)
 
5346
#define DUK_HEAP_STRING_IS_SEALED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_SEALED)
 
5347
#define DUK_HTHREAD_STRING_IS_SEALED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_SEALED)
 
5348
#define DUK_HEAP_STRING_PREVENT_EXTENSIONS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PREVENT_EXTENSIONS)
 
5349
#define DUK_HTHREAD_STRING_PREVENT_EXTENSIONS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PREVENT_EXTENSIONS)
 
5350
#define DUK_HEAP_STRING_FREEZE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FREEZE)
 
5351
#define DUK_HTHREAD_STRING_FREEZE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FREEZE)
 
5352
#define DUK_HEAP_STRING_SEAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SEAL)
 
5353
#define DUK_HTHREAD_STRING_SEAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SEAL)
 
5354
#define DUK_HEAP_STRING_DEFINE_PROPERTIES(heap)                       DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTIES)
 
5355
#define DUK_HTHREAD_STRING_DEFINE_PROPERTIES(thr)                     DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTIES)
 
5356
#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
 
5357
#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
 
5358
#define DUK_HEAP_STRING_CREATE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CREATE)
 
5359
#define DUK_HTHREAD_STRING_CREATE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CREATE)
 
5360
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_NAMES(heap)                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
5361
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_NAMES(thr)                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_NAMES)
 
5362
#define DUK_HEAP_STRING_GET_OWN_PROPERTY_DESCRIPTOR(heap)             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
5363
#define DUK_HTHREAD_STRING_GET_OWN_PROPERTY_DESCRIPTOR(thr)           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_OWN_PROPERTY_DESCRIPTOR)
 
5364
#define DUK_HEAP_STRING_GET_PROTOTYPE_OF(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET_PROTOTYPE_OF)
 
5365
#define DUK_HTHREAD_STRING_GET_PROTOTYPE_OF(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET_PROTOTYPE_OF)
 
5366
#define DUK_HEAP_STRING_PROTOTYPE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
 
5367
#define DUK_HTHREAD_STRING_PROTOTYPE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
 
5368
#define DUK_HEAP_STRING_LENGTH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
 
5369
#define DUK_HTHREAD_STRING_LENGTH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
 
5370
#define DUK_HEAP_STRING_ALERT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ALERT)
 
5371
#define DUK_HTHREAD_STRING_ALERT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ALERT)
 
5372
#define DUK_HEAP_STRING_PRINT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRINT)
 
5373
#define DUK_HTHREAD_STRING_PRINT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRINT)
 
5374
#define DUK_HEAP_STRING_UNESCAPE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UNESCAPE)
 
5375
#define DUK_HTHREAD_STRING_UNESCAPE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UNESCAPE)
 
5376
#define DUK_HEAP_STRING_ESCAPE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPE)
 
5377
#define DUK_HTHREAD_STRING_ESCAPE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPE)
 
5378
#define DUK_HEAP_STRING_ENCODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
5379
#define DUK_HTHREAD_STRING_ENCODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI_COMPONENT)
 
5380
#define DUK_HEAP_STRING_ENCODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENCODE_URI)
 
5381
#define DUK_HTHREAD_STRING_ENCODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENCODE_URI)
 
5382
#define DUK_HEAP_STRING_DECODE_URI_COMPONENT(heap)                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI_COMPONENT)
 
5383
#define DUK_HTHREAD_STRING_DECODE_URI_COMPONENT(thr)                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI_COMPONENT)
 
5384
#define DUK_HEAP_STRING_DECODE_URI(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DECODE_URI)
 
5385
#define DUK_HTHREAD_STRING_DECODE_URI(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DECODE_URI)
 
5386
#define DUK_HEAP_STRING_IS_FINITE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_FINITE)
 
5387
#define DUK_HTHREAD_STRING_IS_FINITE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_FINITE)
 
5388
#define DUK_HEAP_STRING_IS_NAN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IS_NAN)
 
5389
#define DUK_HTHREAD_STRING_IS_NAN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IS_NAN)
 
5390
#define DUK_HEAP_STRING_PARSE_FLOAT(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_FLOAT)
 
5391
#define DUK_HTHREAD_STRING_PARSE_FLOAT(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_FLOAT)
 
5392
#define DUK_HEAP_STRING_PARSE_INT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PARSE_INT)
 
5393
#define DUK_HTHREAD_STRING_PARSE_INT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PARSE_INT)
 
5394
#define DUK_HEAP_STRING_EVAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
 
5395
#define DUK_HTHREAD_STRING_EVAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
 
5396
#define DUK_HEAP_STRING_URI_ERROR(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_URI_ERROR)
 
5397
#define DUK_HTHREAD_STRING_URI_ERROR(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_URI_ERROR)
 
5398
#define DUK_HEAP_STRING_TYPE_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE_ERROR)
 
5399
#define DUK_HTHREAD_STRING_TYPE_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE_ERROR)
 
5400
#define DUK_HEAP_STRING_SYNTAX_ERROR(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SYNTAX_ERROR)
 
5401
#define DUK_HTHREAD_STRING_SYNTAX_ERROR(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SYNTAX_ERROR)
 
5402
#define DUK_HEAP_STRING_REFERENCE_ERROR(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REFERENCE_ERROR)
 
5403
#define DUK_HTHREAD_STRING_REFERENCE_ERROR(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REFERENCE_ERROR)
 
5404
#define DUK_HEAP_STRING_RANGE_ERROR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RANGE_ERROR)
 
5405
#define DUK_HTHREAD_STRING_RANGE_ERROR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RANGE_ERROR)
 
5406
#define DUK_HEAP_STRING_EVAL_ERROR(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL_ERROR)
 
5407
#define DUK_HTHREAD_STRING_EVAL_ERROR(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL_ERROR)
 
5408
#define DUK_HEAP_STRING_BREAK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
 
5409
#define DUK_HTHREAD_STRING_BREAK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
 
5410
#define DUK_HEAP_STRING_CASE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
 
5411
#define DUK_HTHREAD_STRING_CASE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
 
5412
#define DUK_HEAP_STRING_CATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
 
5413
#define DUK_HTHREAD_STRING_CATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
 
5414
#define DUK_HEAP_STRING_CONTINUE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
 
5415
#define DUK_HTHREAD_STRING_CONTINUE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
 
5416
#define DUK_HEAP_STRING_DEBUGGER(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
 
5417
#define DUK_HTHREAD_STRING_DEBUGGER(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
 
5418
#define DUK_HEAP_STRING_DEFAULT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
 
5419
#define DUK_HTHREAD_STRING_DEFAULT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
 
5420
#define DUK_HEAP_STRING_DELETE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
 
5421
#define DUK_HTHREAD_STRING_DELETE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
 
5422
#define DUK_HEAP_STRING_DO(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
 
5423
#define DUK_HTHREAD_STRING_DO(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
 
5424
#define DUK_HEAP_STRING_ELSE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
 
5425
#define DUK_HTHREAD_STRING_ELSE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
 
5426
#define DUK_HEAP_STRING_FINALLY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
 
5427
#define DUK_HTHREAD_STRING_FINALLY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
 
5428
#define DUK_HEAP_STRING_FOR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
 
5429
#define DUK_HTHREAD_STRING_FOR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
 
5430
#define DUK_HEAP_STRING_LC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
 
5431
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
 
5432
#define DUK_HEAP_STRING_IF(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
 
5433
#define DUK_HTHREAD_STRING_IF(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
 
5434
#define DUK_HEAP_STRING_IN(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
 
5435
#define DUK_HTHREAD_STRING_IN(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
 
5436
#define DUK_HEAP_STRING_INSTANCEOF(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
 
5437
#define DUK_HTHREAD_STRING_INSTANCEOF(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
 
5438
#define DUK_HEAP_STRING_NEW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
 
5439
#define DUK_HTHREAD_STRING_NEW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
 
5440
#define DUK_HEAP_STRING_RETURN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
 
5441
#define DUK_HTHREAD_STRING_RETURN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
 
5442
#define DUK_HEAP_STRING_SWITCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
 
5443
#define DUK_HTHREAD_STRING_SWITCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
 
5444
#define DUK_HEAP_STRING_THIS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
 
5445
#define DUK_HTHREAD_STRING_THIS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
 
5446
#define DUK_HEAP_STRING_THROW(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
 
5447
#define DUK_HTHREAD_STRING_THROW(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
 
5448
#define DUK_HEAP_STRING_TRY(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
 
5449
#define DUK_HTHREAD_STRING_TRY(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
 
5450
#define DUK_HEAP_STRING_TYPEOF(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
 
5451
#define DUK_HTHREAD_STRING_TYPEOF(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
 
5452
#define DUK_HEAP_STRING_VAR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
 
5453
#define DUK_HTHREAD_STRING_VAR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
 
5454
#define DUK_HEAP_STRING_VOID(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
 
5455
#define DUK_HTHREAD_STRING_VOID(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
 
5456
#define DUK_HEAP_STRING_WHILE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
 
5457
#define DUK_HTHREAD_STRING_WHILE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
 
5458
#define DUK_HEAP_STRING_WITH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
 
5459
#define DUK_HTHREAD_STRING_WITH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
 
5460
#define DUK_HEAP_STRING_CLASS(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
 
5461
#define DUK_HTHREAD_STRING_CLASS(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
 
5462
#define DUK_HEAP_STRING_CONST(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
 
5463
#define DUK_HTHREAD_STRING_CONST(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
 
5464
#define DUK_HEAP_STRING_ENUM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
 
5465
#define DUK_HTHREAD_STRING_ENUM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
 
5466
#define DUK_HEAP_STRING_EXPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
 
5467
#define DUK_HTHREAD_STRING_EXPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
 
5468
#define DUK_HEAP_STRING_EXTENDS(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
 
5469
#define DUK_HTHREAD_STRING_EXTENDS(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
 
5470
#define DUK_HEAP_STRING_IMPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
 
5471
#define DUK_HTHREAD_STRING_IMPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
 
5472
#define DUK_HEAP_STRING_SUPER(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
 
5473
#define DUK_HTHREAD_STRING_SUPER(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
 
5474
#define DUK_HEAP_STRING_NULL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NULL)
 
5475
#define DUK_HTHREAD_STRING_NULL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NULL)
 
5476
#define DUK_HEAP_STRING_TRUE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
 
5477
#define DUK_HTHREAD_STRING_TRUE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
 
5478
#define DUK_HEAP_STRING_FALSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
 
5479
#define DUK_HTHREAD_STRING_FALSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
 
5480
#define DUK_HEAP_STRING_IMPLEMENTS(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
 
5481
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
 
5482
#define DUK_HEAP_STRING_INTERFACE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
 
5483
#define DUK_HTHREAD_STRING_INTERFACE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
 
5484
#define DUK_HEAP_STRING_LET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
 
5485
#define DUK_HTHREAD_STRING_LET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
 
5486
#define DUK_HEAP_STRING_PACKAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
 
5487
#define DUK_HTHREAD_STRING_PACKAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
 
5488
#define DUK_HEAP_STRING_PRIVATE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
 
5489
#define DUK_HTHREAD_STRING_PRIVATE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
 
5490
#define DUK_HEAP_STRING_PROTECTED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
 
5491
#define DUK_HTHREAD_STRING_PROTECTED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
 
5492
#define DUK_HEAP_STRING_PUBLIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
 
5493
#define DUK_HTHREAD_STRING_PUBLIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
 
5494
#define DUK_HEAP_STRING_STATIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
 
5495
#define DUK_HTHREAD_STRING_STATIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
 
5496
#define DUK_HEAP_STRING_YIELD(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
 
5497
#define DUK_HTHREAD_STRING_YIELD(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
 
5498
 
 
5499
#define DUK_HEAP_NUM_STRINGS                                          323
 
5500
 
 
5501
#define DUK_STRIDX_START_RESERVED                                     278
 
5502
#define DUK_STRIDX_START_STRICT_RESERVED                              314
 
5503
#define DUK_STRIDX_END_RESERVED                                       323                            /* exclusive endpoint */
 
5504
 
 
5505
extern const duk_c_function duk_bi_native_functions[];
 
5506
extern const duk_uint8_t duk_builtins_data[];
 
5507
#ifdef DUK_USE_INITJS
 
5508
extern const duk_uint8_t duk_initjs_data[];
 
5509
#endif  /* DUK_USE_INITJS */
 
5510
 
 
5511
#define DUK_BUILTINS_DATA_LENGTH                                      1314
 
5512
#ifdef DUK_USE_INITJS
 
5513
#define DUK_INITJS_DATA_LENGTH                                        148
 
5514
#endif  /* DUK_USE_INITJS */
 
5515
 
 
5516
#define DUK_BIDX_GLOBAL                                               0
 
5517
#define DUK_BIDX_GLOBAL_ENV                                           1
 
5518
#define DUK_BIDX_OBJECT_CONSTRUCTOR                                   2
 
5519
#define DUK_BIDX_OBJECT_PROTOTYPE                                     3
 
5520
#define DUK_BIDX_FUNCTION_CONSTRUCTOR                                 4
 
5521
#define DUK_BIDX_FUNCTION_PROTOTYPE                                   5
 
5522
#define DUK_BIDX_ARRAY_CONSTRUCTOR                                    6
 
5523
#define DUK_BIDX_ARRAY_PROTOTYPE                                      7
 
5524
#define DUK_BIDX_STRING_CONSTRUCTOR                                   8
 
5525
#define DUK_BIDX_STRING_PROTOTYPE                                     9
 
5526
#define DUK_BIDX_BOOLEAN_CONSTRUCTOR                                  10
 
5527
#define DUK_BIDX_BOOLEAN_PROTOTYPE                                    11
 
5528
#define DUK_BIDX_NUMBER_CONSTRUCTOR                                   12
 
5529
#define DUK_BIDX_NUMBER_PROTOTYPE                                     13
 
5530
#define DUK_BIDX_DATE_CONSTRUCTOR                                     14
 
5531
#define DUK_BIDX_DATE_PROTOTYPE                                       15
 
5532
#define DUK_BIDX_REGEXP_CONSTRUCTOR                                   16
 
5533
#define DUK_BIDX_REGEXP_PROTOTYPE                                     17
 
5534
#define DUK_BIDX_ERROR_CONSTRUCTOR                                    18
 
5535
#define DUK_BIDX_ERROR_PROTOTYPE                                      19
 
5536
#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR                               20
 
5537
#define DUK_BIDX_EVAL_ERROR_PROTOTYPE                                 21
 
5538
#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR                              22
 
5539
#define DUK_BIDX_RANGE_ERROR_PROTOTYPE                                23
 
5540
#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR                          24
 
5541
#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE                            25
 
5542
#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR                             26
 
5543
#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE                               27
 
5544
#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR                               28
 
5545
#define DUK_BIDX_TYPE_ERROR_PROTOTYPE                                 29
 
5546
#define DUK_BIDX_URI_ERROR_CONSTRUCTOR                                30
 
5547
#define DUK_BIDX_URI_ERROR_PROTOTYPE                                  31
 
5548
#define DUK_BIDX_MATH                                                 32
 
5549
#define DUK_BIDX_JSON                                                 33
 
5550
#define DUK_BIDX_TYPE_ERROR_THROWER                                   34
 
5551
#define DUK_BIDX_DUKTAPE                                              35
 
5552
#define DUK_BIDX_THREAD_CONSTRUCTOR                                   36
 
5553
#define DUK_BIDX_THREAD_PROTOTYPE                                     37
 
5554
#define DUK_BIDX_BUFFER_CONSTRUCTOR                                   38
 
5555
#define DUK_BIDX_BUFFER_PROTOTYPE                                     39
 
5556
#define DUK_BIDX_POINTER_CONSTRUCTOR                                  40
 
5557
#define DUK_BIDX_POINTER_PROTOTYPE                                    41
 
5558
#define DUK_BIDX_LOGGER_CONSTRUCTOR                                   42
 
5559
#define DUK_BIDX_LOGGER_PROTOTYPE                                     43
 
5560
#define DUK_BIDX_DOUBLE_ERROR                                         44
 
5561
 
 
5562
#define DUK_NUM_BUILTINS                                              45
 
5563
 
 
5564
#else
 
5565
#error invalid endianness defines
 
5566
#endif
 
5567
#endif  /* DUK_BUILTINS_H_INCLUDED */
 
5568
#line 46 "duk_internal.h"
 
5569
 
 
5570
#line 1 "duk_js_bytecode.h"
 
5571
/*
 
5572
 *  Ecmascript bytecode
 
5573
 */
 
5574
 
 
5575
#ifndef DUK_JS_BYTECODE_H_INCLUDED
 
5576
#define DUK_JS_BYTECODE_H_INCLUDED
 
5577
 
 
5578
/*
 
5579
 *  Logical instruction layout
 
5580
 *  ==========================
 
5581
 *
 
5582
 *  !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
 
5583
 *  !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!
 
5584
 *  +---------------------------------------------------+-----------+
 
5585
 *  !       C         !       B         !      A        !    OP     !
 
5586
 *  +---------------------------------------------------+-----------+
 
5587
 *
 
5588
 *  OP (6 bits):  opcode (DUK_OP_*), access should be fastest
 
5589
 *  A (8 bits):   typically a target register number
 
5590
 *  B (9 bits):   typically first source register/constant number
 
5591
 *  C (9 bits):   typically second source register/constant number
 
5592
 *
 
5593
 *  Some instructions combine BC or ABC together for larger parameter values.
 
5594
 *  Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
 
5595
 *  specific bias.  B and C may denote a register or a constant, see
 
5596
 *  DUK_BC_ISREG() and DUK_BC_ISCONST().
 
5597
 *
 
5598
 *  Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
 
5599
 *  the field layout is logically "CBA".
 
5600
 */ 
 
5601
 
 
5602
typedef duk_uint32_t duk_instr;
 
5603
 
 
5604
#define DUK_DEC_OP(x)               ((x) & 0x3fUL)
 
5605
#define DUK_DEC_A(x)                (((x) >> 6) & 0xffUL)
 
5606
#define DUK_DEC_B(x)                (((x) >> 14) & 0x1ffUL)
 
5607
#define DUK_DEC_C(x)                (((x) >> 23) & 0x1ffUL)
 
5608
#define DUK_DEC_BC(x)               (((x) >> 14) & 0x3ffffUL)
 
5609
#define DUK_DEC_ABC(x)              (((x) >> 6) & 0x3ffffffUL)
 
5610
 
 
5611
#define DUK_ENC_OP_ABC(op,abc)      ((duk_instr) (((abc) << 6) | (op)))
 
5612
#define DUK_ENC_OP_A_BC(op,a,bc)    ((duk_instr) (((bc) << 14) | ((a) << 6) | (op)))
 
5613
#define DUK_ENC_OP_A_B_C(op,a,b,c)  ((duk_instr) (((c) << 23) | ((b) << 14) | ((a) << 6) | (op)))
 
5614
#define DUK_ENC_OP_A_B(op,a,b)      DUK_ENC_OP_A_B_C(op,a,b,0)
 
5615
#define DUK_ENC_OP_A(op,a)          DUK_ENC_OP_A_B_C(op,a,0,0)
 
5616
 
 
5617
/* Constants should be signed so that signed arithmetic involving them
 
5618
 * won't cause values to be coerced accidentally to unsigned.
 
5619
 */
 
5620
#define DUK_BC_OP_MIN               0
 
5621
#define DUK_BC_OP_MAX               0x3fL
 
5622
#define DUK_BC_A_MIN                0
 
5623
#define DUK_BC_A_MAX                0xffL
 
5624
#define DUK_BC_B_MIN                0
 
5625
#define DUK_BC_B_MAX                0x1ffL
 
5626
#define DUK_BC_C_MIN                0
 
5627
#define DUK_BC_C_MAX                0x1ffL
 
5628
#define DUK_BC_BC_MIN               0
 
5629
#define DUK_BC_BC_MAX               0x3ffffL
 
5630
#define DUK_BC_ABC_MIN              0
 
5631
#define DUK_BC_ABC_MAX              0x3ffffffL
 
5632
#define DUK_BC_EXTRAOP_MIN          DUK_BC_A_MIN
 
5633
#define DUK_BC_EXTRAOP_MAX          DUK_BC_A_MAX
 
5634
 
 
5635
#define DUK_OP_LDREG                0 
 
5636
#define DUK_OP_STREG                1
 
5637
#define DUK_OP_LDCONST              2
 
5638
#define DUK_OP_LDINT                3
 
5639
#define DUK_OP_LDINTX               4
 
5640
#define DUK_OP_MPUTOBJ              5
 
5641
#define DUK_OP_MPUTOBJI             6
 
5642
#define DUK_OP_MPUTARR              7
 
5643
#define DUK_OP_MPUTARRI             8
 
5644
#define DUK_OP_NEW                  9
 
5645
#define DUK_OP_NEWI                 10
 
5646
#define DUK_OP_REGEXP               11
 
5647
#define DUK_OP_CSREG                12
 
5648
#define DUK_OP_CSREGI               13
 
5649
#define DUK_OP_GETVAR               14
 
5650
#define DUK_OP_PUTVAR               15
 
5651
#define DUK_OP_DECLVAR              16
 
5652
#define DUK_OP_DELVAR               17
 
5653
#define DUK_OP_CSVAR                18
 
5654
#define DUK_OP_CSVARI               19
 
5655
#define DUK_OP_CLOSURE              20
 
5656
#define DUK_OP_GETPROP              21
 
5657
#define DUK_OP_PUTPROP              22
 
5658
#define DUK_OP_DELPROP              23
 
5659
#define DUK_OP_CSPROP               24
 
5660
#define DUK_OP_CSPROPI              25
 
5661
#define DUK_OP_ADD                  26
 
5662
#define DUK_OP_SUB                  27
 
5663
#define DUK_OP_MUL                  28
 
5664
#define DUK_OP_DIV                  29
 
5665
#define DUK_OP_MOD                  30
 
5666
#define DUK_OP_BAND                 31
 
5667
#define DUK_OP_BOR                  32
 
5668
#define DUK_OP_BXOR                 33
 
5669
#define DUK_OP_BASL                 34
 
5670
#define DUK_OP_BLSR                 35
 
5671
#define DUK_OP_BASR                 36
 
5672
#define DUK_OP_BNOT                 37
 
5673
#define DUK_OP_LNOT                 38
 
5674
#define DUK_OP_EQ                   39
 
5675
#define DUK_OP_NEQ                  40
 
5676
#define DUK_OP_SEQ                  41
 
5677
#define DUK_OP_SNEQ                 42
 
5678
#define DUK_OP_GT                   43
 
5679
#define DUK_OP_GE                   44
 
5680
#define DUK_OP_LT                   45
 
5681
#define DUK_OP_LE                   46
 
5682
#define DUK_OP_IF                   47
 
5683
#define DUK_OP_INSTOF               48
 
5684
#define DUK_OP_IN                   49
 
5685
#define DUK_OP_JUMP                 50
 
5686
#define DUK_OP_RETURN               51
 
5687
#define DUK_OP_CALL                 52
 
5688
#define DUK_OP_CALLI                53
 
5689
#define DUK_OP_LABEL                54
 
5690
#define DUK_OP_ENDLABEL             55
 
5691
#define DUK_OP_BREAK                56
 
5692
#define DUK_OP_CONTINUE             57
 
5693
#define DUK_OP_TRYCATCH             58
 
5694
#define DUK_OP_UNUSED59             59
 
5695
#define DUK_OP_UNUSED60             60
 
5696
#define DUK_OP_EXTRA                61
 
5697
#define DUK_OP_DEBUG                62
 
5698
#define DUK_OP_INVALID              63
 
5699
 
 
5700
/* DUK_OP_EXTRA, sub-operation in A */
 
5701
#define DUK_EXTRAOP_NOP             0
 
5702
#define DUK_EXTRAOP_LDTHIS          1
 
5703
#define DUK_EXTRAOP_LDUNDEF         2
 
5704
#define DUK_EXTRAOP_LDNULL          3
 
5705
#define DUK_EXTRAOP_LDTRUE          4
 
5706
#define DUK_EXTRAOP_LDFALSE         5
 
5707
#define DUK_EXTRAOP_NEWOBJ          6
 
5708
#define DUK_EXTRAOP_NEWARR          7
 
5709
#define DUK_EXTRAOP_SETALEN         8
 
5710
#define DUK_EXTRAOP_TYPEOF          9
 
5711
#define DUK_EXTRAOP_TYPEOFID        10
 
5712
#define DUK_EXTRAOP_TONUM           11
 
5713
#define DUK_EXTRAOP_INITENUM        12
 
5714
#define DUK_EXTRAOP_NEXTENUM        13
 
5715
#define DUK_EXTRAOP_INITSET         14
 
5716
#define DUK_EXTRAOP_INITSETI        15
 
5717
#define DUK_EXTRAOP_INITGET         16
 
5718
#define DUK_EXTRAOP_INITGETI        17
 
5719
#define DUK_EXTRAOP_ENDTRY          18
 
5720
#define DUK_EXTRAOP_ENDCATCH        19
 
5721
#define DUK_EXTRAOP_ENDFIN          20
 
5722
#define DUK_EXTRAOP_THROW           21
 
5723
#define DUK_EXTRAOP_INVLHS          22
 
5724
#define DUK_EXTRAOP_UNM             23
 
5725
#define DUK_EXTRAOP_UNP             24
 
5726
#define DUK_EXTRAOP_INC             25
 
5727
#define DUK_EXTRAOP_DEC             26
 
5728
 
 
5729
/* DUK_OP_DEBUG, sub-operation in A */
 
5730
#define DUK_DEBUGOP_DUMPREG         0
 
5731
#define DUK_DEBUGOP_DUMPREGS        1
 
5732
#define DUK_DEBUGOP_DUMPTHREAD      2
 
5733
#define DUK_DEBUGOP_LOGMARK         3
 
5734
 
 
5735
/* DUK_OP_CALL flags in A */
 
5736
#define DUK_BC_CALL_FLAG_TAILCALL           (1 << 0)
 
5737
#define DUK_BC_CALL_FLAG_EVALCALL           (1 << 1)
 
5738
 
 
5739
/* DUK_OP_TRYCATCH flags in A */
 
5740
#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH     (1 << 0)
 
5741
#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY   (1 << 1)
 
5742
#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING  (1 << 2)
 
5743
#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING   (1 << 3)
 
5744
 
 
5745
/* DUK_OP_RETURN flags in A */
 
5746
#define DUK_BC_RETURN_FLAG_FAST             (1 << 0)
 
5747
#define DUK_BC_RETURN_FLAG_HAVE_RETVAL      (1 << 1)
 
5748
 
 
5749
/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
 
5750
#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE     (1 << 4)  /* use 'undefined' for value automatically */
 
5751
#define DUK_BC_DECLVAR_FLAG_FUNC_DECL       (1 << 5)  /* function declaration */
 
5752
 
 
5753
/* misc constants and helper macros */
 
5754
#define DUK_BC_REGLIMIT             256  /* if B/C is >= this value, refers to a const */
 
5755
#define DUK_BC_ISREG(x)             ((x) < DUK_BC_REGLIMIT)
 
5756
#define DUK_BC_ISCONST(x)           ((x) >= DUK_BC_REGLIMIT)
 
5757
#define DUK_BC_LDINT_BIAS           (1 << 17)
 
5758
#define DUK_BC_LDINTX_SHIFT         18
 
5759
#define DUK_BC_JUMP_BIAS            (1 << 25)
 
5760
 
 
5761
#endif  /* DUK_JS_BYTECODE_H_INCLUDED */
 
5762
 
 
5763
#line 1 "duk_lexer.h"
 
5764
/*
 
5765
 *  Lexer defines.
 
5766
 */
 
5767
 
 
5768
#ifndef DUK_LEXER_H_INCLUDED
 
5769
#define DUK_LEXER_H_INCLUDED
 
5770
 
 
5771
typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, int direct);
 
5772
 
 
5773
/*
 
5774
 *  A token is interpreted as any possible production of InputElementDiv
 
5775
 *  and InputElementRegExp, see E5 Section 7 in its entirety.  Note that
 
5776
 *  the E5 "Token" production does not cover all actual tokens of the
 
5777
 *  language (which is explicitly stated in the specification, Section 7.5).
 
5778
 *  Null and boolean literals are defined as part of both ReservedWord
 
5779
 *  (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions.  Here,
 
5780
 *  null and boolean values have literal tokens, and are not reserved
 
5781
 *  words.
 
5782
 *
 
5783
 *  Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
 
5784
 *  The number tokens always have a non-negative value.  The unary minus
 
5785
 *  operator in "-1.0" is optimized during compilation to yield a single
 
5786
 *  negative constant.
 
5787
 *
 
5788
 *  Token numbering is free except that reserved words are required to be
 
5789
 *  in a continuous range and in a particular order.  See genstrings.py.
 
5790
 */
 
5791
 
 
5792
#define DUK_LEXER_INITCTX(ctx)        duk_lexer_initctx((ctx))
 
5793
 
 
5794
#define DUK_LEXER_SETPOINT(ctx,pt)    duk_lexer_setpoint((ctx), (pt))
 
5795
 
 
5796
#define DUK_LEXER_GETPOINT(ctx,pt)    do { (pt)->offset = (ctx)->offsets[0]; \
 
5797
                                           (pt)->line = (ctx)->lines[0]; } while (0)
 
5798
 
 
5799
/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
 
5800
#define DUK_LEXER_WINDOW_SIZE                     8
 
5801
 
 
5802
#define DUK_TOK_MINVAL                            0
 
5803
 
 
5804
/* returned after EOF (infinite amount) */
 
5805
#define DUK_TOK_EOF                               0
 
5806
 
 
5807
/* line terminator or multi-line comment with internal lineterm (E5 Sections 7.3, 7.4) */
 
5808
#define DUK_TOK_LINETERM                          1
 
5809
 
 
5810
/* single-line comment or multi-line comment without internal lineterm (E5 Section 7.4) */
 
5811
#define DUK_TOK_COMMENT                           2
 
5812
 
 
5813
/* identifier names (E5 Section 7.6) */
 
5814
#define DUK_TOK_IDENTIFIER                        3
 
5815
 
 
5816
/* reserved words: keywords */
 
5817
#define DUK_TOK_START_RESERVED                    4
 
5818
#define DUK_TOK_BREAK                             4
 
5819
#define DUK_TOK_CASE                              5
 
5820
#define DUK_TOK_CATCH                             6
 
5821
#define DUK_TOK_CONTINUE                          7
 
5822
#define DUK_TOK_DEBUGGER                          8
 
5823
#define DUK_TOK_DEFAULT                           9
 
5824
#define DUK_TOK_DELETE                            10
 
5825
#define DUK_TOK_DO                                11
 
5826
#define DUK_TOK_ELSE                              12
 
5827
#define DUK_TOK_FINALLY                           13
 
5828
#define DUK_TOK_FOR                               14
 
5829
#define DUK_TOK_FUNCTION                          15
 
5830
#define DUK_TOK_IF                                16
 
5831
#define DUK_TOK_IN                                17
 
5832
#define DUK_TOK_INSTANCEOF                        18
 
5833
#define DUK_TOK_NEW                               19
 
5834
#define DUK_TOK_RETURN                            20
 
5835
#define DUK_TOK_SWITCH                            21
 
5836
#define DUK_TOK_THIS                              22
 
5837
#define DUK_TOK_THROW                             23
 
5838
#define DUK_TOK_TRY                               24
 
5839
#define DUK_TOK_TYPEOF                            25
 
5840
#define DUK_TOK_VAR                               26
 
5841
#define DUK_TOK_VOID                              27
 
5842
#define DUK_TOK_WHILE                             28
 
5843
#define DUK_TOK_WITH                              29
 
5844
 
 
5845
/* reserved words: future reserved words */
 
5846
#define DUK_TOK_CLASS                             30
 
5847
#define DUK_TOK_CONST                             31
 
5848
#define DUK_TOK_ENUM                              32
 
5849
#define DUK_TOK_EXPORT                            33
 
5850
#define DUK_TOK_EXTENDS                           34
 
5851
#define DUK_TOK_IMPORT                            35
 
5852
#define DUK_TOK_SUPER                             36
 
5853
 
 
5854
/* "null", "true", and "false" are always reserved words.
 
5855
 * Note that "get" and "set" are not!
 
5856
 */
 
5857
#define DUK_TOK_NULL                              37
 
5858
#define DUK_TOK_TRUE                              38
 
5859
#define DUK_TOK_FALSE                             39
 
5860
 
 
5861
/* reserved words: additional future reserved words in strict mode */
 
5862
#define DUK_TOK_START_STRICT_RESERVED             40  /* inclusive */
 
5863
#define DUK_TOK_IMPLEMENTS                        40
 
5864
#define DUK_TOK_INTERFACE                         41
 
5865
#define DUK_TOK_LET                               42
 
5866
#define DUK_TOK_PACKAGE                           43
 
5867
#define DUK_TOK_PRIVATE                           44
 
5868
#define DUK_TOK_PROTECTED                         45
 
5869
#define DUK_TOK_PUBLIC                            46
 
5870
#define DUK_TOK_STATIC                            47
 
5871
#define DUK_TOK_YIELD                             48
 
5872
 
 
5873
#define DUK_TOK_END_RESERVED                      49  /* exclusive */
 
5874
 
 
5875
/* "get" and "set" are tokens but NOT ReservedWords.  They are currently
 
5876
 * parsed and identifiers and these defines are actually now unused.
 
5877
 */
 
5878
#define DUK_TOK_GET                               49
 
5879
#define DUK_TOK_SET                               50
 
5880
 
 
5881
/* punctuators (unlike the spec, also includes "/" and "/=") */
 
5882
#define DUK_TOK_LCURLY                            51
 
5883
#define DUK_TOK_RCURLY                            52
 
5884
#define DUK_TOK_LBRACKET                          53
 
5885
#define DUK_TOK_RBRACKET                          54
 
5886
#define DUK_TOK_LPAREN                            55
 
5887
#define DUK_TOK_RPAREN                            56
 
5888
#define DUK_TOK_PERIOD                            57
 
5889
#define DUK_TOK_SEMICOLON                         58
 
5890
#define DUK_TOK_COMMA                             59
 
5891
#define DUK_TOK_LT                                60
 
5892
#define DUK_TOK_GT                                61
 
5893
#define DUK_TOK_LE                                62
 
5894
#define DUK_TOK_GE                                63
 
5895
#define DUK_TOK_EQ                                64
 
5896
#define DUK_TOK_NEQ                               65
 
5897
#define DUK_TOK_SEQ                               66
 
5898
#define DUK_TOK_SNEQ                              67
 
5899
#define DUK_TOK_ADD                               68
 
5900
#define DUK_TOK_SUB                               69
 
5901
#define DUK_TOK_MUL                               70
 
5902
#define DUK_TOK_DIV                               71
 
5903
#define DUK_TOK_MOD                               72
 
5904
#define DUK_TOK_INCREMENT                         73
 
5905
#define DUK_TOK_DECREMENT                         74
 
5906
#define DUK_TOK_ALSHIFT                           75  /* named "arithmetic" because result is signed */
 
5907
#define DUK_TOK_ARSHIFT                           76
 
5908
#define DUK_TOK_RSHIFT                            77
 
5909
#define DUK_TOK_BAND                              78
 
5910
#define DUK_TOK_BOR                               79
 
5911
#define DUK_TOK_BXOR                              80
 
5912
#define DUK_TOK_LNOT                              81
 
5913
#define DUK_TOK_BNOT                              82
 
5914
#define DUK_TOK_LAND                              83
 
5915
#define DUK_TOK_LOR                               84
 
5916
#define DUK_TOK_QUESTION                          85
 
5917
#define DUK_TOK_COLON                             86
 
5918
#define DUK_TOK_EQUALSIGN                         87
 
5919
#define DUK_TOK_ADD_EQ                            88
 
5920
#define DUK_TOK_SUB_EQ                            89
 
5921
#define DUK_TOK_MUL_EQ                            90
 
5922
#define DUK_TOK_DIV_EQ                            91
 
5923
#define DUK_TOK_MOD_EQ                            92
 
5924
#define DUK_TOK_ALSHIFT_EQ                        93
 
5925
#define DUK_TOK_ARSHIFT_EQ                        94
 
5926
#define DUK_TOK_RSHIFT_EQ                         95
 
5927
#define DUK_TOK_BAND_EQ                           96
 
5928
#define DUK_TOK_BOR_EQ                            97
 
5929
#define DUK_TOK_BXOR_EQ                           98
 
5930
 
 
5931
/* literals (E5 Section 7.8), except null, true, false, which are treated
 
5932
 * like reserved words (above).
 
5933
 */
 
5934
#define DUK_TOK_NUMBER                            99
 
5935
#define DUK_TOK_STRING                            100
 
5936
#define DUK_TOK_REGEXP                            101
 
5937
 
 
5938
#define DUK_TOK_MAXVAL                            101  /* inclusive */
 
5939
 
 
5940
/* Convert heap string index to a token (reserved words) */
 
5941
#define DUK_STRIDX_TO_TOK(x)                        ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
 
5942
 
 
5943
/* Sanity check */
 
5944
#if (DUK_TOK_MAXVAL > 255)
 
5945
#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
 
5946
#endif
 
5947
 
 
5948
/* Sanity checks for string and token defines */
 
5949
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
 
5950
#error mismatch in token defines
 
5951
#endif
 
5952
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
 
5953
#error mismatch in token defines
 
5954
#endif
 
5955
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
 
5956
#error mismatch in token defines
 
5957
#endif
 
5958
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
 
5959
#error mismatch in token defines
 
5960
#endif
 
5961
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
 
5962
#error mismatch in token defines
 
5963
#endif
 
5964
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
 
5965
#error mismatch in token defines
 
5966
#endif
 
5967
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
 
5968
#error mismatch in token defines
 
5969
#endif
 
5970
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
 
5971
#error mismatch in token defines
 
5972
#endif
 
5973
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
 
5974
#error mismatch in token defines
 
5975
#endif
 
5976
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
 
5977
#error mismatch in token defines
 
5978
#endif
 
5979
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
 
5980
#error mismatch in token defines
 
5981
#endif
 
5982
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
 
5983
#error mismatch in token defines
 
5984
#endif
 
5985
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
 
5986
#error mismatch in token defines
 
5987
#endif
 
5988
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
 
5989
#error mismatch in token defines
 
5990
#endif
 
5991
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
 
5992
#error mismatch in token defines
 
5993
#endif
 
5994
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
 
5995
#error mismatch in token defines
 
5996
#endif
 
5997
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
 
5998
#error mismatch in token defines
 
5999
#endif
 
6000
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
 
6001
#error mismatch in token defines
 
6002
#endif
 
6003
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
 
6004
#error mismatch in token defines
 
6005
#endif
 
6006
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
 
6007
#error mismatch in token defines
 
6008
#endif
 
6009
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
 
6010
#error mismatch in token defines
 
6011
#endif
 
6012
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
 
6013
#error mismatch in token defines
 
6014
#endif
 
6015
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
 
6016
#error mismatch in token defines
 
6017
#endif
 
6018
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
 
6019
#error mismatch in token defines
 
6020
#endif
 
6021
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
 
6022
#error mismatch in token defines
 
6023
#endif
 
6024
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
 
6025
#error mismatch in token defines
 
6026
#endif
 
6027
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
 
6028
#error mismatch in token defines
 
6029
#endif
 
6030
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
 
6031
#error mismatch in token defines
 
6032
#endif
 
6033
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
 
6034
#error mismatch in token defines
 
6035
#endif
 
6036
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
 
6037
#error mismatch in token defines
 
6038
#endif
 
6039
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
 
6040
#error mismatch in token defines
 
6041
#endif
 
6042
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
 
6043
#error mismatch in token defines
 
6044
#endif
 
6045
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
 
6046
#error mismatch in token defines
 
6047
#endif
 
6048
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NULL) != DUK_TOK_NULL)
 
6049
#error mismatch in token defines
 
6050
#endif
 
6051
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
 
6052
#error mismatch in token defines
 
6053
#endif
 
6054
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
 
6055
#error mismatch in token defines
 
6056
#endif
 
6057
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
 
6058
#error mismatch in token defines
 
6059
#endif
 
6060
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
 
6061
#error mismatch in token defines
 
6062
#endif
 
6063
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
 
6064
#error mismatch in token defines
 
6065
#endif
 
6066
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
 
6067
#error mismatch in token defines
 
6068
#endif
 
6069
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
 
6070
#error mismatch in token defines
 
6071
#endif
 
6072
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
 
6073
#error mismatch in token defines
 
6074
#endif
 
6075
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
 
6076
#error mismatch in token defines
 
6077
#endif
 
6078
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
 
6079
#error mismatch in token defines
 
6080
#endif
 
6081
#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
 
6082
#error mismatch in token defines
 
6083
#endif
 
6084
 
 
6085
/* Regexp tokens */
 
6086
#define DUK_RETOK_EOF                              0
 
6087
#define DUK_RETOK_DISJUNCTION                      1
 
6088
#define DUK_RETOK_QUANTIFIER                       2
 
6089
#define DUK_RETOK_ASSERT_START                     3
 
6090
#define DUK_RETOK_ASSERT_END                       4
 
6091
#define DUK_RETOK_ASSERT_WORD_BOUNDARY             5
 
6092
#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY         6
 
6093
#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD       7
 
6094
#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD       8
 
6095
#define DUK_RETOK_ATOM_PERIOD                      9
 
6096
#define DUK_RETOK_ATOM_CHAR                        10
 
6097
#define DUK_RETOK_ATOM_DIGIT                       11
 
6098
#define DUK_RETOK_ATOM_NOT_DIGIT                   12
 
6099
#define DUK_RETOK_ATOM_WHITE                       13
 
6100
#define DUK_RETOK_ATOM_NOT_WHITE                   14
 
6101
#define DUK_RETOK_ATOM_WORD_CHAR                   15
 
6102
#define DUK_RETOK_ATOM_NOT_WORD_CHAR               16
 
6103
#define DUK_RETOK_ATOM_BACKREFERENCE               17
 
6104
#define DUK_RETOK_ATOM_START_CAPTURE_GROUP         18
 
6105
#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP      19
 
6106
#define DUK_RETOK_ATOM_START_CHARCLASS             20
 
6107
#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED    21
 
6108
#define DUK_RETOK_ATOM_END_GROUP                   22
 
6109
 
 
6110
/* constants for duk_lexer_ctx.buf */
 
6111
#define DUK_LEXER_TEMP_BUF_INITIAL                 64
 
6112
#define DUK_LEXER_TEMP_BUF_LIMIT                   256
 
6113
 
 
6114
/* A token value.  Can be memcpy()'d, but note that slot1/slot2 values are on the valstack. */
 
6115
struct duk_token {
 
6116
        int t;                  /* token type (with reserved word identification) */
 
6117
        int t_nores;            /* token type (with reserved words as DUK_TOK_IDENTIFER) */
 
6118
        double num;             /* numeric value of token */
 
6119
        duk_hstring *str1;      /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
 
6120
        duk_hstring *str2;      /* string 2 of token (borrowed, stored to ctx->slot1_idx) */
 
6121
        int num_escapes;        /* number of escapes and line continuations (for directive prologue) */
 
6122
        int start_line;         /* start line of token (first char) */
 
6123
        int end_line;           /* end line of token (char after last token char) */
 
6124
        int start_offset;       /* start byte offset of token in lexer input */
 
6125
        int lineterm;           /* token was preceded by a lineterm */
 
6126
        int allow_auto_semi;    /* token allows automatic semicolon insertion (eof or preceded by newline) */
 
6127
};
 
6128
 
 
6129
#define DUK_RE_QUANTIFIER_INFINITE         ((duk_uint32_t) 0xffffffffUL)
 
6130
 
 
6131
/* A regexp token value. */
 
6132
struct duk_re_token {
 
6133
        int t;                  /* token type */
 
6134
        duk_uint32_t num;       /* numeric value (character, count) */
 
6135
        duk_uint32_t qmin;
 
6136
        duk_uint32_t qmax;
 
6137
        int greedy;
 
6138
};
 
6139
 
 
6140
/* A structure for 'snapshotting' a point for rewinding */
 
6141
struct duk_lexer_point {
 
6142
        int offset;
 
6143
        int line;
 
6144
};
 
6145
 
 
6146
/* Lexer context.  Same context is used for Ecmascript and Regexp parsing. */
 
6147
struct duk_lexer_ctx {
 
6148
        duk_hthread *thr;                       /* thread; minimizes argument passing */
 
6149
 
 
6150
        duk_uint8_t *input;
 
6151
        int input_length;
 
6152
        int window[DUK_LEXER_WINDOW_SIZE];      /* window of unicode code points */
 
6153
        int offsets[DUK_LEXER_WINDOW_SIZE];     /* input byte offset for each char */
 
6154
        int lines[DUK_LEXER_WINDOW_SIZE];       /* input lines for each char */
 
6155
        int input_offset;                       /* input offset for window leading edge (not window[0]) */
 
6156
        int input_line;                         /* input linenumber at input_offset (not window[0]), init to 1 */
 
6157
 
 
6158
        int slot1_idx;                          /* valstack slot for 1st token value */
 
6159
        int slot2_idx;                          /* valstack slot for 2nd token value */
 
6160
        int buf_idx;                            /* valstack slot for temp buffer */
 
6161
        duk_hbuffer_dynamic *buf;               /* temp accumulation buffer (on valstack) */
 
6162
 
 
6163
        duk_int_t token_count;                  /* number of tokens parsed */
 
6164
        duk_int_t token_limit;                  /* maximum token count before error (sanity backstop) */
 
6165
};
 
6166
 
 
6167
/*
 
6168
 *  Prototypes
 
6169
 */
 
6170
 
 
6171
void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
 
6172
 
 
6173
void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
 
6174
 
 
6175
void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
 
6176
                                      duk_token *out_token,
 
6177
                                      int strict_mode,
 
6178
                                      int regexp_mode);
 
6179
#ifdef DUK_USE_REGEXP_SUPPORT
 
6180
void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
 
6181
void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
 
6182
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
6183
 
 
6184
#endif  /* DUK_LEXER_H_INCLUDED */
 
6185
 
 
6186
#line 1 "duk_js_compiler.h"
 
6187
/*
 
6188
 *  Ecmascript compiler.
 
6189
 */
 
6190
 
 
6191
#ifndef DUK_JS_COMPILER_H_INCLUDED
 
6192
#define DUK_JS_COMPILER_H_INCLUDED
 
6193
 
 
6194
/* ecmascript compiler limits */
 
6195
#if defined(DUK_USE_DEEP_C_STACK)
 
6196
#define DUK_COMPILER_RECURSION_LIMIT       2500
 
6197
#else
 
6198
#define DUK_COMPILER_RECURSION_LIMIT       50
 
6199
#endif
 
6200
#define DUK_COMPILER_TOKEN_LIMIT           100000000  /* 1e8: protects against deeply nested inner functions */
 
6201
 
 
6202
/* maximum loopcount for peephole optimization */
 
6203
#define DUK_COMPILER_PEEPHOLE_MAXITER      3
 
6204
 
 
6205
/* maximum bytecode length in instructions */
 
6206
#define DUK_COMPILER_MAX_BYTECODE_LENGTH   (256 * 1024 * 1024)  /* 1 GB */
 
6207
 
 
6208
/*
 
6209
 *  Compiler intermediate values
 
6210
 *
 
6211
 *  Intermediate values describe either plain values (e.g. strings or
 
6212
 *  numbers) or binary operations which have not yet been coerced into
 
6213
 *  either a left-hand-side or right-hand-side role (e.g. object property).
 
6214
 */
 
6215
 
 
6216
#define DUK_IVAL_NONE          0   /* no value */
 
6217
#define DUK_IVAL_PLAIN         1   /* register, constant, or value */
 
6218
#define DUK_IVAL_ARITH         2   /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
 
6219
#define DUK_IVAL_PROP          3   /* property access */
 
6220
#define DUK_IVAL_VAR           4   /* variable access */
 
6221
 
 
6222
#define DUK_ISPEC_NONE         0   /* no value */
 
6223
#define DUK_ISPEC_VALUE        1   /* value resides in 'valstack_idx' */
 
6224
#define DUK_ISPEC_REGCONST     2   /* value resides in a register or constant */
 
6225
 
 
6226
/* bit mask which indicates that a regconst is a constant instead of a register */
 
6227
#define DUK_JS_CONST_MARKER    0x80000000
 
6228
 
 
6229
typedef struct {
 
6230
        int t;                      /* DUK_ISPEC_XXX */
 
6231
        int regconst;
 
6232
        int valstack_idx;           /* always set; points to a reserved valstack slot */
 
6233
} duk_ispec;
 
6234
 
 
6235
typedef struct {
 
6236
        /*
 
6237
         *  PLAIN: x1
 
6238
         *  ARITH: x1 <op> x2
 
6239
         *  PROP: x1.x2
 
6240
         *  VAR: x1 (name)
 
6241
         */
 
6242
 
 
6243
        int t;                      /* DUK_IVAL_XXX */
 
6244
        int op;                     /* bytecode opcode for binary ops */
 
6245
        duk_ispec x1;
 
6246
        duk_ispec x2;
 
6247
} duk_ivalue;
 
6248
 
 
6249
/*
 
6250
 *  Bytecode instruction representation during compilation
 
6251
 *
 
6252
 *  Contains the actual instruction and (optionally) debug info.
 
6253
 */
 
6254
 
 
6255
struct duk_compiler_instr {
 
6256
        duk_instr ins;
 
6257
#if defined(DUK_USE_PC2LINE)
 
6258
        duk_uint32_t line;
 
6259
#endif
 
6260
};
 
6261
 
 
6262
/*
 
6263
 *  Compiler state
 
6264
 */
 
6265
 
 
6266
#define DUK_LABEL_FLAG_ALLOW_BREAK       (1 << 0)
 
6267
#define DUK_LABEL_FLAG_ALLOW_CONTINUE    (1 << 1)
 
6268
 
 
6269
#define DUK_DECL_TYPE_VAR                0
 
6270
#define DUK_DECL_TYPE_FUNC               1
 
6271
 
 
6272
/* FIXME: optimize to 16 bytes */
 
6273
typedef struct {
 
6274
        int flags;
 
6275
        int label_id;           /* numeric label_id */
 
6276
        duk_hstring *h_label;   /* borrowed label name */
 
6277
        int catch_depth;        /* catch depth at point of definition */
 
6278
        int pc_label;           /* pc of label statement:
 
6279
                                 * pc+1: break jump site
 
6280
                                 * pc+2: continue jump site
 
6281
                                 */
 
6282
 
 
6283
        /* Fast jumps (which avoid longjmp) jump directly to the jump sites
 
6284
         * which are always known even while the iteration/switch statement
 
6285
         * is still being parsed.  A final peephole pass "straightens out"
 
6286
         * the jumps.
 
6287
         */
 
6288
} duk_labelinfo;
 
6289
 
 
6290
/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
 
6291
struct duk_compiler_func {
 
6292
        /* These pointers are at the start of the struct so that they pack
 
6293
         * nicely.  Mixing pointers and integer values is bad on some
 
6294
         * platforms (e.g. if int is 32 bits and pointers are 64 bits).
 
6295
         */
 
6296
 
 
6297
        duk_hstring *h_name;                /* function name (borrowed reference), ends up in _name */
 
6298
        duk_hbuffer_dynamic *h_code;        /* C array of duk_compiler_instr */
 
6299
        duk_hobject *h_consts;              /* array */
 
6300
        duk_hobject *h_funcs;               /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
 
6301
                                             * offset/line points to closing brace to allow skipping on pass 2
 
6302
                                             */
 
6303
        duk_hobject *h_decls;               /* array of declarations: [ name1, val1, name2, val2, ... ]
 
6304
                                             * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
 
6305
                                             * record function and variable declarations in pass 1
 
6306
                                             */
 
6307
        duk_hobject *h_labelnames;          /* array of active label names */
 
6308
        duk_hbuffer_dynamic *h_labelinfos;  /* C array of duk_labelinfo */
 
6309
        duk_hobject *h_argnames;            /* array of formal argument names (-> _formals) */
 
6310
        duk_hobject *h_varmap;              /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
 
6311
 
 
6312
        int is_function;                    /* is an actual function (not global/eval code) */
 
6313
        int is_eval;                        /* is eval code */
 
6314
        int is_global;                      /* is global code */
 
6315
        int is_setget;                      /* is a setter/getter */
 
6316
        int is_decl;                        /* is a function declaration (as opposed to function expression) */
 
6317
        int is_strict;                      /* function is strict */
 
6318
        int in_directive_prologue;          /* parsing in "directive prologue", recognize directives */
 
6319
        int in_scanning;                    /* parsing in "scanning" phase (first pass) */
 
6320
        int may_direct_eval;                /* function may call direct eval */
 
6321
        int id_access_arguments;            /* function refers to 'arguments' identifier */
 
6322
        int id_access_slow;                 /* function makes one or more slow path accesses */
 
6323
        int is_arguments_shadowed;          /* argument/function declaration shadows 'arguments' */
 
6324
        int needs_shuffle;                  /* function needs shuffle registers */
 
6325
        int num_formals;                    /* number of formal arguments */
 
6326
        int reg_stmt_value;                 /* register for writing value of 'non-empty' statements (global or eval code) */
 
6327
 
 
6328
        int reject_regexp_in_adv;           /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
 
6329
 
 
6330
        int code_idx;
 
6331
        int consts_idx;
 
6332
        int funcs_idx;
 
6333
        int fnum_next;
 
6334
        int decls_idx;
 
6335
        int labelnames_idx;
 
6336
        int labelinfos_idx;
 
6337
        int argnames_idx;
 
6338
        int varmap_idx;
 
6339
 
 
6340
        /* temp reg handling */
 
6341
        int temp_first;                     /* first register that is a temporary (below: variables) */
 
6342
        int temp_next;                      /* next temporary register to allocate */
 
6343
        int temp_max;                       /* highest value of temp_reg (temp_max - 1 is highest used reg) */
 
6344
 
 
6345
        /* shuffle registers if large number of regs/consts */
 
6346
        int shuffle1;
 
6347
        int shuffle2;
 
6348
        int shuffle3;
 
6349
 
 
6350
        /* statement id allocation (running counter) */
 
6351
        int stmt_next;
 
6352
 
 
6353
        /* label handling */
 
6354
        int label_next;
 
6355
 
 
6356
        /* catch stack book-keeping */
 
6357
        int catch_depth;                    /* catch stack depth */
 
6358
 
 
6359
        /* with stack book-keeping (affects identifier lookups) */
 
6360
        int with_depth;
 
6361
 
 
6362
        /* stats for current expression being parsed */
 
6363
        int nud_count;
 
6364
        int led_count;
 
6365
        int paren_level;                    /* parenthesis count, 0 = top level */
 
6366
        int expr_lhs;                       /* expression is left-hand-side compatible */
 
6367
        int allow_in;                       /* current paren level allows 'in' token */
 
6368
};
 
6369
 
 
6370
struct duk_compiler_ctx {
 
6371
        duk_hthread *thr;
 
6372
 
 
6373
        /* filename being compiled (ends up in functions' '_filename' property) */
 
6374
        duk_hstring *h_filename;            /* borrowed reference */
 
6375
 
 
6376
        /* lexing (tokenization) state (contains two valstack slot indices) */
 
6377
        duk_lexer_ctx lex;
 
6378
 
 
6379
        /* current and previous token for parsing */
 
6380
        duk_token prev_token;
 
6381
        duk_token curr_token;
 
6382
        int tok11_idx;                      /* curr_token slot1 (matches 'lex' slot1_idx) */
 
6383
        int tok12_idx;                      /* curr_token slot2 (matches 'lex' slot2_idx) */
 
6384
        int tok21_idx;                      /* prev_token slot1 */
 
6385
        int tok22_idx;                      /* prev_token slot2 */
 
6386
 
 
6387
        /* recursion limit */
 
6388
        int recursion_depth;
 
6389
        int recursion_limit;
 
6390
 
 
6391
        /* current function being compiled (embedded instead of pointer for more compact access) */
 
6392
        duk_compiler_func curr_func;
 
6393
};
 
6394
 
 
6395
/*
 
6396
 *  Prototypes
 
6397
 */
 
6398
 
 
6399
#define DUK_JS_COMPILE_FLAG_EVAL      (1 << 0)  /* source is eval code (not program) */
 
6400
#define DUK_JS_COMPILE_FLAG_STRICT    (1 << 1)  /* strict outer context */
 
6401
#define DUK_JS_COMPILE_FLAG_FUNCEXPR  (1 << 2)  /* source is a function expression (used for Function constructor) */
 
6402
 
 
6403
void duk_js_compile(duk_hthread *thr, int flags);
 
6404
 
 
6405
#endif  /* DUK_JS_COMPILER_H_INCLUDED */
 
6406
 
 
6407
#line 1 "duk_regexp.h"
 
6408
/*
 
6409
 *  Regular expression structs, constants, and bytecode defines.
 
6410
 */
 
6411
 
 
6412
#ifndef DUK_REGEXP_H_INCLUDED
 
6413
#define DUK_REGEXP_H_INCLUDED
 
6414
 
 
6415
/* maximum bytecode copies for {n,m} quantifiers */
 
6416
#define DUK_RE_MAX_ATOM_COPIES             1000
 
6417
 
 
6418
/* regexp compilation limits */
 
6419
#if defined(DUK_USE_DEEP_C_STACK)
 
6420
#define DUK_RE_COMPILE_RECURSION_LIMIT     1000
 
6421
#else
 
6422
#define DUK_RE_COMPILE_RECURSION_LIMIT     100
 
6423
#endif
 
6424
#define DUK_RE_COMPILE_TOKEN_LIMIT         100000000L   /* 1e8 */
 
6425
 
 
6426
/* regexp execution limits */
 
6427
#if defined(DUK_USE_DEEP_C_STACK)
 
6428
#define DUK_RE_EXECUTE_RECURSION_LIMIT     1000
 
6429
#else
 
6430
#define DUK_RE_EXECUTE_RECURSION_LIMIT     100
 
6431
#endif
 
6432
#define DUK_RE_EXECUTE_STEPS_LIMIT         1000000000L  /* 1e9 */
 
6433
 
 
6434
/* regexp opcodes */
 
6435
#define DUK_REOP_MATCH                     1
 
6436
#define DUK_REOP_CHAR                      2
 
6437
#define DUK_REOP_PERIOD                    3
 
6438
#define DUK_REOP_RANGES                    4
 
6439
#define DUK_REOP_INVRANGES                 5
 
6440
#define DUK_REOP_JUMP                      6
 
6441
#define DUK_REOP_SPLIT1                    7
 
6442
#define DUK_REOP_SPLIT2                    8
 
6443
#define DUK_REOP_SQMINIMAL                 9
 
6444
#define DUK_REOP_SQGREEDY                  10
 
6445
#define DUK_REOP_SAVE                      11
 
6446
#define DUK_REOP_WIPERANGE                 12
 
6447
#define DUK_REOP_LOOKPOS                   13
 
6448
#define DUK_REOP_LOOKNEG                   14
 
6449
#define DUK_REOP_BACKREFERENCE             15
 
6450
#define DUK_REOP_ASSERT_START              16
 
6451
#define DUK_REOP_ASSERT_END                17
 
6452
#define DUK_REOP_ASSERT_WORD_BOUNDARY      18
 
6453
#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY  19
 
6454
 
 
6455
/* flags */
 
6456
#define DUK_RE_FLAG_GLOBAL                 (1 << 0)
 
6457
#define DUK_RE_FLAG_IGNORE_CASE            (1 << 1)
 
6458
#define DUK_RE_FLAG_MULTILINE              (1 << 2)
 
6459
 
 
6460
struct duk_re_matcher_ctx {
 
6461
        duk_hthread *thr;
 
6462
 
 
6463
        duk_uint32_t re_flags;
 
6464
        duk_uint8_t *input;
 
6465
        duk_uint8_t *input_end;
 
6466
        duk_uint8_t *bytecode;
 
6467
        duk_uint8_t *bytecode_end;
 
6468
        duk_uint8_t **saved;            /* allocated from valstack (fixed buffer) */
 
6469
        duk_uint32_t nsaved;
 
6470
        duk_uint32_t recursion_depth;
 
6471
        duk_uint32_t recursion_limit;
 
6472
        duk_uint32_t steps_count;
 
6473
        duk_uint32_t steps_limit;
 
6474
};
 
6475
 
 
6476
struct duk_re_compiler_ctx {
 
6477
        duk_hthread *thr;
 
6478
 
 
6479
        duk_uint32_t re_flags;
 
6480
        duk_lexer_ctx lex;
 
6481
        duk_re_token curr_token;
 
6482
        duk_hbuffer_dynamic *buf;
 
6483
        duk_uint32_t captures;  /* highest capture number emitted so far (used as: ++captures) */
 
6484
        duk_uint32_t highest_backref;
 
6485
        duk_uint32_t recursion_depth;
 
6486
        duk_uint32_t recursion_limit;
 
6487
        duk_uint32_t nranges;   /* internal temporary value, used for char classes */
 
6488
};
 
6489
 
 
6490
/*
 
6491
 *  Prototypes
 
6492
 */
 
6493
 
 
6494
void duk_regexp_compile(duk_hthread *thr);
 
6495
void duk_regexp_create_instance(duk_hthread *thr);
 
6496
void duk_regexp_match(duk_hthread *thr);
 
6497
void duk_regexp_match_force_global(duk_hthread *thr);  /* hacky helper for String.prototype.split() */
 
6498
 
 
6499
#endif  /* DUK_REGEXP_H_INCLUDED */
 
6500
 
 
6501
#line 1 "duk_tval.h"
 
6502
/*
 
6503
 *  Tagged type definition (duk_tval) and accessor macros.
 
6504
 *
 
6505
 *  Access all fields through the accessor macros, as the representation
 
6506
 *  is quite tricky.
 
6507
 *
 
6508
 *  There are two packed type alternatives: an 8-byte representation
 
6509
 *  based on an IEEE double (preferred for compactness), and a 12-byte
 
6510
 *  representation (portability).  The latter is needed also in e.g.
 
6511
 *  64-bit environments (it usually pads to 16 bytes per value).
 
6512
 *
 
6513
 *  Selecting the tagged type format involves many trade-offs (memory
 
6514
 *  use, size and performance of generated code, portability, etc),
 
6515
 *  see doc/types.txt for a detailed discussion (especially of how the
 
6516
 *  IEEE double format is used to pack tagged values).
 
6517
 *
 
6518
 *  NB: because macro arguments are often expressions, macros should
 
6519
 *  avoid evaluating their argument more than once.
 
6520
 */
 
6521
 
 
6522
#ifndef DUK_TVAL_H_INCLUDED
 
6523
#define DUK_TVAL_H_INCLUDED
 
6524
 
 
6525
/* sanity */
 
6526
#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
 
6527
#error unsupported: cannot determine byte order variant
 
6528
#endif
 
6529
 
 
6530
#ifdef DUK_USE_PACKED_TVAL
 
6531
/* ======================================================================== */
 
6532
 
 
6533
/*
 
6534
 *  Packed 8-byte representation
 
6535
 */
 
6536
 
 
6537
/* sanity */
 
6538
#if !defined(DUK_USE_PACKED_TVAL_POSSIBLE)
 
6539
#error packed representation not supported
 
6540
#endif
 
6541
 
 
6542
/* use duk_double_union as duk_tval directly */
 
6543
typedef union duk_double_union duk_tval;
 
6544
 
 
6545
/* tags */
 
6546
#define DUK_TAG_NORMALIZED_NAN    0x7ff8UL   /* the NaN variant we use */
 
6547
/* avoid tag 0xfff0, no risk of confusion with negative infinity */
 
6548
#define DUK_TAG_UNDEFINED         0xfff1UL   /* embed: 0 or 1 (normal or unused) */
 
6549
#define DUK_TAG_NULL              0xfff2UL   /* embed: nothing */
 
6550
#define DUK_TAG_BOOLEAN           0xfff3UL   /* embed: 0 or 1 (false or true) */
 
6551
/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
 
6552
#define DUK_TAG_POINTER           0xfff4UL   /* embed: void ptr */
 
6553
#define DUK_TAG_STRING            0xfff5UL   /* embed: duk_hstring ptr */
 
6554
#define DUK_TAG_OBJECT            0xfff6UL   /* embed: duk_hobject ptr */
 
6555
#define DUK_TAG_BUFFER            0xfff7UL   /* embed: duk_hbuffer ptr */
 
6556
 
 
6557
/* for convenience */
 
6558
#define DUK_XTAG_UNDEFINED_ACTUAL 0xfff10000UL
 
6559
#define DUK_XTAG_UNDEFINED_UNUSED 0xfff10001UL
 
6560
#define DUK_XTAG_NULL             0xfff20000UL
 
6561
#define DUK_XTAG_BOOLEAN_FALSE    0xfff30000UL
 
6562
#define DUK_XTAG_BOOLEAN_TRUE     0xfff30001UL
 
6563
 
 
6564
#define DUK__TVAL_SET_UNDEFINED_ACTUAL_FULL(v)      DUK_DBLUNION_SET_HIGH32_ZERO_LOW32((v), DUK_XTAG_UNDEFINED_ACTUAL)
 
6565
#define DUK__TVAL_SET_UNDEFINED_ACTUAL_NOTFULL(v)   DUK_DBLUNION_SET_HIGH32((v), DUK_XTAG_UNDEFINED_ACTUAL)
 
6566
#define DUK__TVAL_SET_UNDEFINED_UNUSED_FULL(v)      DUK_DBLUNION_SET_HIGH32_ZERO_LOW32((v), DUK_XTAG_UNDEFINED_UNUSED)
 
6567
#define DUK__TVAL_SET_UNDEFINED_UNUSED_NOTFULL(v)   DUK_DBLUNION_SET_HIGH32((v), DUK_XTAG_UNDEFINED_UNUSED)
 
6568
 
 
6569
/* Note: 16-bit initializer suffices (unlike for undefined/boolean) */
 
6570
#define DUK__TVAL_SET_NULL_FULL(v)     DUK_DBLUNION_SET_HIGH32_ZERO_LOW32((v), DUK_XTAG_NULL)
 
6571
#define DUK__TVAL_SET_NULL_NOTFULL(v)  do { \
 
6572
                (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
 
6573
        } while (0)
 
6574
 
 
6575
#define DUK__TVAL_SET_BOOLEAN_FULL(v,val)    DUK_DBLUNION_SET_HIGH32_ZERO_LOW32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) val))
 
6576
#define DUK__TVAL_SET_BOOLEAN_NOTFULL(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
 
6577
 
 
6578
/* assumes that caller has normalized a possible NaN value of 'val', otherwise trouble ahead;
 
6579
 * no notfull variant
 
6580
 */
 
6581
#define DUK__TVAL_SET_NUMBER_FULL(v,val)     DUK_DBLUNION_SET_DOUBLE((v), (val))
 
6582
#define DUK__TVAL_SET_NUMBER_NOTFULL(v,val)  DUK_DBLUNION_SET_DOUBLE((v), (val))
 
6583
 
 
6584
/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
 
6585
#ifdef DUK_USE_64BIT_OPS
 
6586
#ifdef DUK_USE_DOUBLE_ME
 
6587
#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag)  do { \
 
6588
                (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
 
6589
        } while (0)
 
6590
#else
 
6591
#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag)  do { \
 
6592
                (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
 
6593
        } while (0)
 
6594
#endif
 
6595
#else  /* DUK_USE_64BIT_OPS */
 
6596
#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag)  do { \
 
6597
                (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
 
6598
                (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
 
6599
        } while (0)
 
6600
#endif  /* DUK_USE_64BIT_OPS */
 
6601
 
 
6602
/* select actual setters */
 
6603
#ifdef DUK_USE_FULL_TVAL
 
6604
#define DUK_TVAL_SET_UNDEFINED_ACTUAL(v)    DUK__TVAL_SET_UNDEFINED_ACTUAL_FULL((v))
 
6605
#define DUK_TVAL_SET_UNDEFINED_UNUSED(v)    DUK__TVAL_SET_UNDEFINED_UNUSED_FULL((v))
 
6606
#define DUK_TVAL_SET_NULL(v)                DUK__TVAL_SET_NULL_FULL((v))
 
6607
#define DUK_TVAL_SET_BOOLEAN(v,i)           DUK__TVAL_SET_BOOLEAN_FULL((v),(i))
 
6608
#define DUK_TVAL_SET_NUMBER(v,d)            DUK__TVAL_SET_NUMBER_FULL((v),(d))
 
6609
#define DUK_TVAL_SET_NAN(v)                 DUK__TVAL_SET_NAN_FULL((v))
 
6610
#else
 
6611
#define DUK_TVAL_SET_UNDEFINED_ACTUAL(v)    DUK__TVAL_SET_UNDEFINED_ACTUAL_NOTFULL((v))
 
6612
#define DUK_TVAL_SET_UNDEFINED_UNUSED(v)    DUK__TVAL_SET_UNDEFINED_UNUSED_NOTFULL((v))
 
6613
#define DUK_TVAL_SET_NULL(v)                DUK__TVAL_SET_NULL_NOTFULL((v))
 
6614
#define DUK_TVAL_SET_BOOLEAN(v,i)           DUK__TVAL_SET_BOOLEAN_NOTFULL((v),(i))
 
6615
#define DUK_TVAL_SET_NUMBER(v,d)            DUK__TVAL_SET_NUMBER_NOTFULL((v),(d))
 
6616
#define DUK_TVAL_SET_NAN(v)                 DUK__TVAL_SET_NAN_NOTFULL((v))
 
6617
#endif
 
6618
 
 
6619
#define DUK_TVAL_SET_STRING(v,h)            DUK__TVAL_SET_TAGGEDPOINTER((v),(h),DUK_TAG_STRING)
 
6620
#define DUK_TVAL_SET_OBJECT(v,h)            DUK__TVAL_SET_TAGGEDPOINTER((v),(h),DUK_TAG_OBJECT)
 
6621
#define DUK_TVAL_SET_BUFFER(v,h)            DUK__TVAL_SET_TAGGEDPOINTER((v),(h),DUK_TAG_BUFFER)
 
6622
#define DUK_TVAL_SET_POINTER(v,p)           DUK__TVAL_SET_TAGGEDPOINTER((v),(p),DUK_TAG_POINTER)
 
6623
 
 
6624
#define DUK_TVAL_SET_TVAL(v,x)              do { *(v) = *(x); } while (0)
 
6625
 
 
6626
/* getters */
 
6627
#define DUK_TVAL_GET_BOOLEAN(v)             ((int) (v)->us[DUK_DBL_IDX_US1])
 
6628
#define DUK_TVAL_GET_NUMBER(v)              ((v)->d)
 
6629
#define DUK_TVAL_GET_STRING(v)              ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
 
6630
#define DUK_TVAL_GET_OBJECT(v)              ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
 
6631
#define DUK_TVAL_GET_BUFFER(v)              ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
 
6632
#define DUK_TVAL_GET_POINTER(v)             ((void *) (v)->vp[DUK_DBL_IDX_VP1])
 
6633
#define DUK_TVAL_GET_HEAPHDR(v)             ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
 
6634
 
 
6635
/* decoding */
 
6636
#define DUK_TVAL_GET_TAG(v)                 ((int) (v)->us[DUK_DBL_IDX_US0])
 
6637
 
 
6638
#define DUK_TVAL_IS_UNDEFINED(v)            (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
 
6639
#define DUK_TVAL_IS_UNDEFINED_ACTUAL(v)     ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_UNDEFINED_ACTUAL)
 
6640
#define DUK_TVAL_IS_UNDEFINED_UNUSED(v)     ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_UNDEFINED_UNUSED)
 
6641
#define DUK_TVAL_IS_NULL(v)                 (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
 
6642
#define DUK_TVAL_IS_BOOLEAN(v)              (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
 
6643
#define DUK_TVAL_IS_BOOLEAN_TRUE(v)         ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
 
6644
#define DUK_TVAL_IS_BOOLEAN_FALSE(v)        ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
 
6645
#define DUK_TVAL_IS_STRING(v)               (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
 
6646
#define DUK_TVAL_IS_OBJECT(v)               (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
 
6647
#define DUK_TVAL_IS_BUFFER(v)               (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
 
6648
#define DUK_TVAL_IS_POINTER(v)              (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
 
6649
/* 0xfff0 is -Infinity */
 
6650
#define DUK_TVAL_IS_NUMBER(v)               (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
 
6651
 
 
6652
#define DUK_TVAL_IS_HEAP_ALLOCATED(v)       (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
 
6653
 
 
6654
#else  /* DUK_USE_PACKED_TVAL */
 
6655
/* ======================================================================== */
 
6656
 
 
6657
/*
 
6658
 *  Portable 12-byte representation
 
6659
 */
 
6660
 
 
6661
#ifdef DUK_USE_FULL_TVAL
 
6662
#error no 'full' tagged values in 12-byte representation
 
6663
#endif
 
6664
 
 
6665
typedef struct duk_tval_struct duk_tval;
 
6666
 
 
6667
struct duk_tval_struct {
 
6668
        int t;
 
6669
        union {
 
6670
                double d;
 
6671
                int i;
 
6672
                void *voidptr;
 
6673
                duk_hstring *hstring;
 
6674
                duk_hobject *hobject;
 
6675
                duk_hcompiledfunction *hcompiledfunction;
 
6676
                duk_hnativefunction *hnativefunction;
 
6677
                duk_hthread *hthread;
 
6678
                duk_hbuffer *hbuffer;
 
6679
                duk_heaphdr *heaphdr;
 
6680
        } v;
 
6681
};
 
6682
 
 
6683
#define DUK__TAG_NUMBER               0  /* not exposed */
 
6684
#define DUK_TAG_UNDEFINED             1
 
6685
#define DUK_TAG_NULL                  2
 
6686
#define DUK_TAG_BOOLEAN               3
 
6687
#define DUK_TAG_POINTER               4
 
6688
#define DUK_TAG_STRING                5
 
6689
#define DUK_TAG_OBJECT                6
 
6690
#define DUK_TAG_BUFFER                7
 
6691
 
 
6692
/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
 
6693
 * to support the 8-byte representation.  Further, it is a non-heap-allocated
 
6694
 * type so it should come before DUK_TAG_STRING.  Finally, it should not break
 
6695
 * the tag value ranges covered by case-clauses in a switch-case.
 
6696
 */
 
6697
 
 
6698
/* setters */
 
6699
#define DUK_TVAL_SET_UNDEFINED_ACTUAL(tv)  do { \
 
6700
                (tv)->t = DUK_TAG_UNDEFINED; \
 
6701
                (tv)->v.i = 0; \
 
6702
        } while (0)
 
6703
 
 
6704
#define DUK_TVAL_SET_UNDEFINED_UNUSED(tv)  do { \
 
6705
                (tv)->t = DUK_TAG_UNDEFINED; \
 
6706
                (tv)->v.i = 1; \
 
6707
        } while (0)
 
6708
 
 
6709
#define DUK_TVAL_SET_NULL(tv)  do { \
 
6710
                (tv)->t = DUK_TAG_NULL; \
 
6711
        } while (0)
 
6712
 
 
6713
#define DUK_TVAL_SET_BOOLEAN(tv,val)  do { \
 
6714
                (tv)->t = DUK_TAG_BOOLEAN; \
 
6715
                (tv)->v.i = (val); \
 
6716
        } while (0)
 
6717
 
 
6718
#define DUK_TVAL_SET_NUMBER(tv,val)  do { \
 
6719
                (tv)->t = DUK__TAG_NUMBER; \
 
6720
                (tv)->v.d = (val); \
 
6721
        } while (0)
 
6722
 
 
6723
#define DUK_TVAL_SET_STRING(tv,hptr)  do { \
 
6724
                (tv)->t = DUK_TAG_STRING; \
 
6725
                (tv)->v.hstring = (hptr); \
 
6726
        } while (0)
 
6727
 
 
6728
#define DUK_TVAL_SET_OBJECT(tv,hptr)  do { \
 
6729
                (tv)->t = DUK_TAG_OBJECT; \
 
6730
                (tv)->v.hobject = (hptr); \
 
6731
        } while (0)
 
6732
 
 
6733
#define DUK_TVAL_SET_BUFFER(tv,hptr)  do { \
 
6734
                (tv)->t = DUK_TAG_BUFFER; \
 
6735
                (tv)->v.hbuffer = (hptr); \
 
6736
        } while (0)
 
6737
 
 
6738
#define DUK_TVAL_SET_POINTER(tv,hptr)  do { \
 
6739
                (tv)->t = DUK_TAG_POINTER; \
 
6740
                (tv)->v.voidptr = (hptr); \
 
6741
        } while (0)
 
6742
 
 
6743
#define DUK_TVAL_SET_NAN(tv)  do { \
 
6744
                /* in non-packed representation we don't care about which NaN is used */ \
 
6745
                (tv)->t = DUK__TAG_NUMBER; \
 
6746
                (tv)->v.d = DUK_DOUBLE_NAN; \
 
6747
        } while (0)
 
6748
 
 
6749
#define DUK_TVAL_SET_TVAL(v,x)              do { *(v) = *(x); } while (0)
 
6750
 
 
6751
/* getters */
 
6752
#define DUK_TVAL_GET_BOOLEAN(tv)           ((tv)->v.i)
 
6753
#define DUK_TVAL_GET_NUMBER(tv)            ((tv)->v.d)
 
6754
#define DUK_TVAL_GET_STRING(tv)            ((tv)->v.hstring)
 
6755
#define DUK_TVAL_GET_OBJECT(tv)            ((tv)->v.hobject)
 
6756
#define DUK_TVAL_GET_BUFFER(tv)            ((tv)->v.hbuffer)
 
6757
#define DUK_TVAL_GET_POINTER(tv)           ((tv)->v.voidptr)
 
6758
#define DUK_TVAL_GET_HEAPHDR(tv)           ((tv)->v.heaphdr)
 
6759
 
 
6760
/* decoding */
 
6761
#define DUK_TVAL_GET_TAG(tv)               ((tv)->t)
 
6762
#define DUK_TVAL_IS_NUMBER(tv)             ((tv)->t == DUK__TAG_NUMBER)
 
6763
#define DUK_TVAL_IS_UNDEFINED(tv)          ((tv)->t == DUK_TAG_UNDEFINED)
 
6764
#define DUK_TVAL_IS_UNDEFINED_ACTUAL(tv)   (((tv)->t == DUK_TAG_UNDEFINED) && ((tv)->v.i == 0))
 
6765
#define DUK_TVAL_IS_UNDEFINED_UNUSED(tv)   (((tv)->t == DUK_TAG_UNDEFINED) && ((tv)->v.i != 0))
 
6766
#define DUK_TVAL_IS_NULL(tv)               ((tv)->t == DUK_TAG_NULL)
 
6767
#define DUK_TVAL_IS_BOOLEAN(tv)            ((tv)->t == DUK_TAG_BOOLEAN)
 
6768
#define DUK_TVAL_IS_BOOLEAN_TRUE(tv)       (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
 
6769
#define DUK_TVAL_IS_BOOLEAN_FALSE(tv)      (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
 
6770
#define DUK_TVAL_IS_STRING(tv)             ((tv)->t == DUK_TAG_STRING)
 
6771
#define DUK_TVAL_IS_OBJECT(tv)             ((tv)->t == DUK_TAG_OBJECT)
 
6772
#define DUK_TVAL_IS_BUFFER(tv)             ((tv)->t == DUK_TAG_BUFFER)
 
6773
#define DUK_TVAL_IS_POINTER(tv)            ((tv)->t == DUK_TAG_POINTER)
 
6774
 
 
6775
#define DUK_TVAL_IS_HEAP_ALLOCATED(tv)     ((tv)->t >= DUK_TAG_STRING)
 
6776
 
 
6777
#endif  /* DUK_USE_PACKED_TVAL */
 
6778
 
 
6779
/*
 
6780
 *  Convenience (independent of representation)
 
6781
 */
 
6782
 
 
6783
#define DUK_TVAL_SET_BOOLEAN_TRUE(v)        DUK_TVAL_SET_BOOLEAN(v, 1)
 
6784
#define DUK_TVAL_SET_BOOLEAN_FALSE(v)       DUK_TVAL_SET_BOOLEAN(v, 0)
 
6785
 
 
6786
#endif  /* DUK_TVAL_H_INCLUDED */
 
6787
 
 
6788
#line 1 "duk_heaphdr.h"
 
6789
/*
 
6790
 *  Heap header definition and assorted macros, including ref counting.
 
6791
 *  Access all fields through the accessor macros.
 
6792
 */
 
6793
 
 
6794
#ifndef DUK_HEAPHDR_H_INCLUDED
 
6795
#define DUK_HEAPHDR_H_INCLUDED
 
6796
 
 
6797
/*
 
6798
 *  Common heap header
 
6799
 *
 
6800
 *  All heap objects share the same flags and refcount fields.  Objects other
 
6801
 *  than strings also need to have a single or double linked list pointers
 
6802
 *  for insertion into the "heap allocated" list.  Strings are held in the
 
6803
 *  heap-wide string table so they don't need link pointers.
 
6804
 *
 
6805
 *  Technically, 'h_refcount' must be wide enough to guarantee that it cannot
 
6806
 *  wrap (otherwise objects might be freed incorrectly after wrapping).  This
 
6807
 *  means essentially that the refcount field must be as wide as data pointers.
 
6808
 *  On 64-bit platforms this means that the refcount needs to be 64 bits even
 
6809
 *  if an 'int' is 32 bits.  This is a bit unfortunate, and compromising on
 
6810
 *  this might be reasonable in the future.
 
6811
 *
 
6812
 *  Heap header size on 32-bit platforms: 8 bytes without reference counting,
 
6813
 *  16 bytes with reference counting.
 
6814
 */
 
6815
 
 
6816
struct duk_heaphdr {
 
6817
        duk_uint32_t h_flags;
 
6818
#if defined(DUK_USE_REFERENCE_COUNTING)
 
6819
        size_t h_refcount;
 
6820
#endif
 
6821
        duk_heaphdr *h_next;
 
6822
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
 
6823
        /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
 
6824
        duk_heaphdr *h_prev;
 
6825
#endif
 
6826
};
 
6827
 
 
6828
struct duk_heaphdr_string {
 
6829
        duk_uint32_t h_flags;
 
6830
#if defined(DUK_USE_REFERENCE_COUNTING)
 
6831
        size_t h_refcount;
 
6832
#endif
 
6833
};
 
6834
 
 
6835
#define DUK_HEAPHDR_FLAGS_TYPE_MASK      0x00000003UL
 
6836
#define DUK_HEAPHDR_FLAGS_FLAG_MASK      (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
 
6837
 
 
6838
                                             /* 2 bits for heap type */
 
6839
#define DUK_HEAPHDR_FLAGS_HEAP_START     2   /* 4 heap flags */
 
6840
#define DUK_HEAPHDR_FLAGS_USER_START     6   /* 26 user flags */
 
6841
 
 
6842
#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
 
6843
#define DUK_HEAPHDR_USER_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_USER_START + (n))
 
6844
#define DUK_HEAPHDR_HEAP_FLAG(n)         (1 << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
 
6845
#define DUK_HEAPHDR_USER_FLAG(n)         (1 << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
 
6846
 
 
6847
#define DUK_HEAPHDR_FLAG_REACHABLE       DUK_HEAPHDR_HEAP_FLAG(0)  /* mark-and-sweep: reachable */
 
6848
#define DUK_HEAPHDR_FLAG_TEMPROOT        DUK_HEAPHDR_HEAP_FLAG(1)  /* mark-and-sweep: children not processed */
 
6849
#define DUK_HEAPHDR_FLAG_FINALIZABLE     DUK_HEAPHDR_HEAP_FLAG(2)  /* mark-and-sweep: finalizable (on current pass) */
 
6850
#define DUK_HEAPHDR_FLAG_FINALIZED       DUK_HEAPHDR_HEAP_FLAG(3)  /* mark-and-sweep: finalized (on previous pass) */
 
6851
 
 
6852
#define DUK_HTYPE_MIN                    1
 
6853
#define DUK_HTYPE_STRING                 1
 
6854
#define DUK_HTYPE_OBJECT                 2
 
6855
#define DUK_HTYPE_BUFFER                 3
 
6856
#define DUK_HTYPE_MAX                    3
 
6857
 
 
6858
#define DUK_HEAPHDR_GET_NEXT(h)       ((h)->h_next)
 
6859
#define DUK_HEAPHDR_SET_NEXT(h,val)   do { \
 
6860
                (h)->h_next = (val); \
 
6861
        } while (0)
 
6862
 
 
6863
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
 
6864
#define DUK_HEAPHDR_GET_PREV(h)       ((h)->h_prev)
 
6865
#define DUK_HEAPHDR_SET_PREV(h,val)   do { \
 
6866
                (h)->h_prev = (val); \
 
6867
        } while (0)
 
6868
#endif
 
6869
 
 
6870
#if defined(DUK_USE_REFERENCE_COUNTING)
 
6871
#define DUK_HEAPHDR_GET_REFCOUNT(h)   ((h)->h_refcount)
 
6872
#define DUK_HEAPHDR_SET_REFCOUNT(h,val)  do { \
 
6873
                (h)->h_refcount = (val); \
 
6874
        } while (0)
 
6875
#else
 
6876
/* refcount macros not defined without refcounting, caller must #ifdef now */
 
6877
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
6878
 
 
6879
/*
 
6880
 *  Note: type is treated as a field separate from flags, so some masking is
 
6881
 *  involved in the macros below.
 
6882
 */
 
6883
 
 
6884
#define DUK_HEAPHDR_GET_FLAGS(h)      ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
 
6885
#define DUK_HEAPHDR_SET_FLAGS(h,val)  do { \
 
6886
                (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
 
6887
        } while (0)
 
6888
 
 
6889
#define DUK_HEAPHDR_GET_TYPE(h)       ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
 
6890
#define DUK_HEAPHDR_SET_TYPE(h,val)   do { \
 
6891
                (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
 
6892
        } while (0)
 
6893
 
 
6894
#define DUK_HEAPHDR_HTYPE_VALID(h)    ( \
 
6895
        DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
 
6896
        DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
 
6897
        )
 
6898
 
 
6899
#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval)  do { \
 
6900
                (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
 
6901
                               ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
 
6902
        } while (0)
 
6903
 
 
6904
#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits)  do { \
 
6905
                DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
 
6906
                (h)->h_flags |= (bits); \
 
6907
        } while (0)
 
6908
 
 
6909
#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits)  do { \
 
6910
                DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
 
6911
                (h)->h_flags &= ~((bits)); \
 
6912
        } while (0)
 
6913
 
 
6914
#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits)  (((h)->h_flags & (bits)) != 0)
 
6915
 
 
6916
#define DUK_HEAPHDR_SET_REACHABLE(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
 
6917
#define DUK_HEAPHDR_CLEAR_REACHABLE(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
 
6918
#define DUK_HEAPHDR_HAS_REACHABLE(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
 
6919
 
 
6920
#define DUK_HEAPHDR_SET_TEMPROOT(h)       DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
 
6921
#define DUK_HEAPHDR_CLEAR_TEMPROOT(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
 
6922
#define DUK_HEAPHDR_HAS_TEMPROOT(h)       DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
 
6923
 
 
6924
#define DUK_HEAPHDR_SET_FINALIZABLE(h)    DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
 
6925
#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
 
6926
#define DUK_HEAPHDR_HAS_FINALIZABLE(h)    DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
 
6927
 
 
6928
#define DUK_HEAPHDR_SET_FINALIZED(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
 
6929
#define DUK_HEAPHDR_CLEAR_FINALIZED(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
 
6930
#define DUK_HEAPHDR_HAS_FINALIZED(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
 
6931
 
 
6932
/* get or set a range of flags; m=first bit number, n=number of bits */
 
6933
#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n)  (((h)->h_flags >> (m)) & ((1 << (n)) - 1))
 
6934
 
 
6935
#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v)  do { \
 
6936
                (h)->h_flags = \
 
6937
                        ((h)->h_flags & (~(((1 << (n)) - 1) << (m)))) \
 
6938
                        | ((v) << (m)); \
 
6939
        } while (0)
 
6940
 
 
6941
/* init pointer fields to null */
 
6942
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
 
6943
#define DUK_HEAPHDR_INIT_NULLS(h)       do { \
 
6944
                (h)->h_next = NULL; \
 
6945
        } while (0)
 
6946
#else
 
6947
#define DUK_HEAPHDR_INIT_NULLS(h)       do { \
 
6948
                (h)->h_next = NULL; \
 
6949
                (h)->h_prev = NULL; \
 
6950
        } while (0)
 
6951
#endif
 
6952
 
 
6953
#define DUK_HEAPHDR_STRING_INIT_NULLS(h)  /* currently nop */
 
6954
 
 
6955
/*
 
6956
 *  Reference counting helper macros.  The macros take a thread argument
 
6957
 *  and must thus always be executed in a specific thread context.  The
 
6958
 *  thread argument is needed for features like finalization.  Currently
 
6959
 *  it is not required for INCREF, but it is included just in case.
 
6960
 *
 
6961
 *  Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
 
6962
 *  defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
 
6963
 *  around them.
 
6964
 */
 
6965
 
 
6966
#if defined(DUK_USE_REFERENCE_COUNTING)
 
6967
 
 
6968
#define DUK_TVAL_INCREF(thr,tv)                duk_heap_tval_incref((tv))
 
6969
#define DUK_TVAL_DECREF(thr,tv)                duk_heap_tval_decref((thr),(tv))
 
6970
#define DUK__HEAPHDR_INCREF(thr,h)             duk_heap_heaphdr_incref((h))
 
6971
#define DUK__HEAPHDR_DECREF(thr,h)             duk_heap_heaphdr_decref((thr),(h))
 
6972
#define DUK_HEAPHDR_INCREF(thr,h)              DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
 
6973
#define DUK_HEAPHDR_DECREF(thr,h)              DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
 
6974
#define DUK_HSTRING_INCREF(thr,h)              DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
 
6975
#define DUK_HSTRING_DECREF(thr,h)              DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
 
6976
#define DUK_HOBJECT_INCREF(thr,h)              DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
 
6977
#define DUK_HOBJECT_DECREF(thr,h)              DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
 
6978
#define DUK_HBUFFER_INCREF(thr,h)              DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
 
6979
#define DUK_HBUFFER_DECREF(thr,h)              DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
 
6980
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h)    DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
 
6981
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h)    DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
 
6982
#define DUK_HNATIVEFUNCTION_INCREF(thr,h)      DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
 
6983
#define DUK_HNATIVEFUNCTION_DECREF(thr,h)      DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
 
6984
#define DUK_HTHREAD_INCREF(thr,h)              DUK__HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
 
6985
#define DUK_HTHREAD_DECREF(thr,h)              DUK__HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
 
6986
 
 
6987
#else  /* DUK_USE_REFERENCE_COUNTING */
 
6988
 
 
6989
#define DUK_TVAL_INCREF(thr,v)                 /* nop */
 
6990
#define DUK_TVAL_DECREF(thr,v)                 /* nop */
 
6991
#define DUK_HEAPHDR_INCREF(thr,h)              /* nop */
 
6992
#define DUK_HEAPHDR_DECREF(thr,h)              /* nop */
 
6993
#define DUK_HSTRING_INCREF(thr,h)              /* nop */
 
6994
#define DUK_HSTRING_DECREF(thr,h)              /* nop */
 
6995
#define DUK_HOBJECT_INCREF(thr,h)              /* nop */
 
6996
#define DUK_HOBJECT_DECREF(thr,h)              /* nop */
 
6997
#define DUK_HBUFFER_INCREF(thr,h)              /* nop */
 
6998
#define DUK_HBUFFER_DECREF(thr,h)              /* nop */
 
6999
#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h)    /* nop */
 
7000
#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h)    /* nop */
 
7001
#define DUK_HNATIVEFUNCTION_INCREF(thr,h)      /* nop */
 
7002
#define DUK_HNATIVEFUNCTION_DECREF(thr,h)      /* nop */
 
7003
#define DUK_HTHREAD_INCREF(thr,h)              /* nop */
 
7004
#define DUK_HTHREAD_DECREF(thr,h)              /* nop */
 
7005
 
 
7006
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
7007
 
 
7008
#endif  /* DUK_HEAPHDR_H_INCLUDED */
 
7009
 
 
7010
#line 1 "duk_api_internal.h"
 
7011
/*
 
7012
 *  Internal API calls which have (stack and other) semantics
 
7013
 *  similar to the public API.
 
7014
 */
 
7015
 
 
7016
#ifndef DUK_API_INTERNAL_H_INCLUDED
 
7017
#define DUK_API_INTERNAL_H_INCLUDED
 
7018
 
 
7019
/* duk_push_sprintf constants */
 
7020
#define DUK_PUSH_SPRINTF_INITIAL_SIZE  256
 
7021
#define DUK_PUSH_SPRINTF_SANITY_LIMIT  (1*1024*1024*1024)
 
7022
 
 
7023
/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
 
7024
 * blamed as source of error for error fileName / lineNumber.
 
7025
 */
 
7026
#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE  (1 << 24)
 
7027
 
 
7028
int duk_check_valstack_resize(duk_context *ctx, unsigned int min_new_size, int allow_shrink);
 
7029
void duk_require_valstack_resize(duk_context *ctx, unsigned int min_new_size, int allow_shrink);
 
7030
 
 
7031
int duk_check_stack_raw(duk_context *ctx, unsigned int extra);
 
7032
void duk_require_stack_raw(duk_context *ctx, unsigned int extra);
 
7033
 
 
7034
duk_tval *duk_get_tval(duk_context *ctx, int index);
 
7035
duk_tval *duk_require_tval(duk_context *ctx, int index);
 
7036
void duk_push_tval(duk_context *ctx, duk_tval *tv);
 
7037
 
 
7038
void duk_push_this_check_object_coercible(duk_context *ctx);   /* push the current 'this' binding; throw TypeError
 
7039
                                                                * if binding is not object coercible (CheckObjectCoercible).
 
7040
                                                                */
 
7041
duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);       /* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
 
7042
duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);       /* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
 
7043
 
 
7044
void duk_push_u32(duk_context *ctx, duk_uint32_t val);
 
7045
 
 
7046
/* internal helper for looking up a tagged type */
 
7047
#define  DUK_GETTAGGED_FLAG_ALLOW_NULL  (1 << 24)
 
7048
#define  DUK_GETTAGGED_FLAG_CHECK_CLASS (1 << 25)
 
7049
#define  DUK_GETTAGGED_CLASS_SHIFT      16
 
7050
 
 
7051
duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, int index, duk_int_t flags_and_tag);
 
7052
 
 
7053
duk_hstring *duk_get_hstring(duk_context *ctx, int index);
 
7054
duk_hobject *duk_get_hobject(duk_context *ctx, int index);
 
7055
duk_hbuffer *duk_get_hbuffer(duk_context *ctx, int index);
 
7056
duk_hthread *duk_get_hthread(duk_context *ctx, int index);
 
7057
duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, int index);
 
7058
duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, int index);
 
7059
 
 
7060
#define duk_get_hobject_with_class(ctx,index,classnum) \
 
7061
        ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \
 
7062
                DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL | \
 
7063
                DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT)))
 
7064
 
 
7065
/* XXX: add specific getters for e.g. thread; duk_get_hobject_with_flags()
 
7066
 * could be the underlying primitive?
 
7067
 */
 
7068
 
 
7069
duk_hstring *duk_to_hstring(duk_context *ctx, int index);
 
7070
int duk_to_int_clamped_raw(duk_context *ctx, int index, int minval, int maxval, int *out_clamped);  /* out_clamped=NULL, RangeError if outside range */
 
7071
int duk_to_int_clamped(duk_context *ctx, int index, int minval, int maxval);
 
7072
int duk_to_int_check_range(duk_context *ctx, int index, int minval, int maxval);
 
7073
 
 
7074
duk_hstring *duk_require_hstring(duk_context *ctx, int index);
 
7075
duk_hobject *duk_require_hobject(duk_context *ctx, int index);
 
7076
duk_hbuffer *duk_require_hbuffer(duk_context *ctx, int index);
 
7077
duk_hthread *duk_require_hthread(duk_context *ctx, int index);
 
7078
duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, int index);
 
7079
duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, int index);
 
7080
 
 
7081
#define duk_require_hobject_with_class(ctx,index,classnum) \
 
7082
        ((duk_hobject *) duk_get_tagged_heaphdr_raw((ctx), (index), \
 
7083
                DUK_TAG_OBJECT | \
 
7084
                DUK_GETTAGGED_FLAG_CHECK_CLASS | ((classnum) << DUK_GETTAGGED_CLASS_SHIFT)))
 
7085
 
 
7086
void duk_push_unused(duk_context *ctx);
 
7087
void duk_push_hstring(duk_context *ctx, duk_hstring *h);
 
7088
void duk_push_hstring_stridx(duk_context *ctx, int stridx);
 
7089
void duk_push_hobject(duk_context *ctx, duk_hobject *h);
 
7090
void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
 
7091
void duk_push_builtin(duk_context *ctx, int builtin_idx);
 
7092
int duk_push_object_helper(duk_context *ctx, int hobject_flags_and_class, int prototype_bidx);
 
7093
int duk_push_object_helper_proto(duk_context *ctx, int hobject_flags_and_class, duk_hobject *proto);
 
7094
int duk_push_object_internal(duk_context *ctx);
 
7095
int duk_push_compiledfunction(duk_context *ctx);
 
7096
void duk_push_c_function_nospecial(duk_context *ctx, duk_c_function func, int nargs);
 
7097
void duk_push_c_function_noconstruct_nospecial(duk_context *ctx, duk_c_function func, int nargs);
 
7098
 
 
7099
int duk_get_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx);     /* [] -> [val] */
 
7100
int duk_put_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx);     /* [val] -> [] */
 
7101
int duk_del_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx);     /* [] -> [] */
 
7102
int duk_has_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx);     /* [] -> [] */
 
7103
 
 
7104
int duk_get_prop_stridx_boolean(duk_context *ctx, int obj_index, duk_small_int_t stridx, int *out_has_prop);  /* [] -> [] */
 
7105
 
 
7106
void duk_def_prop(duk_context *ctx, int obj_index, int desc_flags);  /* [key val] -> [] */
 
7107
void duk_def_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index, int desc_flags);  /* [val] -> [] */
 
7108
void duk_def_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx, int desc_flags);  /* [val] -> [] */
 
7109
void duk_def_prop_stridx_builtin(duk_context *ctx, int obj_index, unsigned int stridx, unsigned int builtin_idx, int desc_flags);  /* [] -> [] */
 
7110
 
 
7111
void duk_def_prop_stridx_thrower(duk_context *ctx, int obj_index, unsigned int stridx, int desc_flags);  /* [] -> [] */
 
7112
 
 
7113
#endif  /* DUK_API_INTERNAL_H_INCLUDED */
 
7114
 
 
7115
#line 1 "duk_hstring.h"
 
7116
/*
 
7117
 *  Heap string representation.
 
7118
 *
 
7119
 *  Strings are byte sequences ordinarily stored in extended UTF-8 format,
 
7120
 *  allowing values larger than the official UTF-8 range (used internally)
 
7121
 *  and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
 
7122
 *  Strings may also be invalid UTF-8 altogether which is the case e.g. with
 
7123
 *  strings used as internal property names and raw buffers converted to
 
7124
 *  strings.  In such cases the 'clen' field contains an inaccurate value.
 
7125
 *
 
7126
 *  Ecmascript requires support for 32-bit long strings.  However, since each
 
7127
 *  16-bit codepoint can take 3 bytes in CESU-8, this representation can only
 
7128
 *  support about 1.4G codepoint long strings in extreme cases.  This is not
 
7129
 *  really a practical issue.
 
7130
 */
 
7131
 
 
7132
#ifndef DUK_HSTRING_H_INCLUDED
 
7133
#define DUK_HSTRING_H_INCLUDED
 
7134
 
 
7135
/* Impose a maximum string length for now.  Restricted artificially to
 
7136
 * ensure adding a heap header length won't overflow size_t.  The limit
 
7137
 * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
 
7138
 *
 
7139
 * E5.1 makes provisions to support strings longer than 4G characters.
 
7140
 * This limit should be eliminated on 64-bit platforms (and increased
 
7141
 * closer to maximum support on 32-bit platforms).
 
7142
 */
 
7143
#define DUK_HSTRING_MAX_BYTELEN                     (0x7fffffffUL)
 
7144
 
 
7145
/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
 
7146
 * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
 
7147
 * regexp bytecode is), and "contains non-BMP characters".  These are not
 
7148
 * needed right now.
 
7149
 */
 
7150
 
 
7151
#define DUK_HSTRING_FLAG_ARRIDX                     DUK_HEAPHDR_USER_FLAG(0)  /* string is a valid array index */
 
7152
#define DUK_HSTRING_FLAG_INTERNAL                   DUK_HEAPHDR_USER_FLAG(1)  /* string is internal */
 
7153
#define DUK_HSTRING_FLAG_RESERVED_WORD              DUK_HEAPHDR_USER_FLAG(2)  /* string is a reserved word (non-strict) */
 
7154
#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD       DUK_HEAPHDR_USER_FLAG(3)  /* string is a reserved word (strict) */
 
7155
#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS          DUK_HEAPHDR_USER_FLAG(4)  /* string is 'eval' or 'arguments' */
 
7156
 
 
7157
#define DUK_HSTRING_HAS_ARRIDX(x)                   DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
 
7158
#define DUK_HSTRING_HAS_INTERNAL(x)                 DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
 
7159
#define DUK_HSTRING_HAS_RESERVED_WORD(x)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
 
7160
#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
 
7161
#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x)        DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
 
7162
 
 
7163
#define DUK_HSTRING_SET_ARRIDX(x)                   DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
 
7164
#define DUK_HSTRING_SET_INTERNAL(x)                 DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
 
7165
#define DUK_HSTRING_SET_RESERVED_WORD(x)            DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
 
7166
#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x)     DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
 
7167
#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x)        DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
 
7168
 
 
7169
#define DUK_HSTRING_CLEAR_ARRIDX(x)                 DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
 
7170
#define DUK_HSTRING_CLEAR_INTERNAL(x)               DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
 
7171
#define DUK_HSTRING_CLEAR_RESERVED_WORD(x)          DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
 
7172
#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x)   DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
 
7173
#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x)      DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
 
7174
 
 
7175
#define DUK_HSTRING_IS_ASCII(x)                     ((x)->blen == (x)->clen)
 
7176
#define DUK_HSTRING_IS_EMPTY(x)                     ((x)->blen == 0)
 
7177
 
 
7178
#define DUK_HSTRING_GET_HASH(x)                     ((x)->hash)
 
7179
#define DUK_HSTRING_GET_BYTELEN(x)                  ((x)->blen)
 
7180
#define DUK_HSTRING_GET_CHARLEN(x)                  ((x)->clen)
 
7181
#define DUK_HSTRING_GET_DATA(x)                     ((duk_uint8_t *) ((x) + 1))
 
7182
#define DUK_HSTRING_GET_DATA_END(x)                 (((duk_uint8_t *) ((x) + 1)) + ((x)->blen))
 
7183
 
 
7184
/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
 
7185
#define DUK_HSTRING_NO_ARRAY_INDEX  (0xffffffffUL)
 
7186
 
 
7187
/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
 
7188
 * avoids helper call if string has no array index value.
 
7189
 */
 
7190
#define DUK_HSTRING_GET_ARRIDX_FAST(h)  \
 
7191
        (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
 
7192
 
 
7193
/* slower but more compact variant */
 
7194
#define DUK_HSTRING_GET_ARRIDX_SLOW(h)  \
 
7195
        (duk_js_to_arrayindex_string_helper((h)))
 
7196
 
 
7197
/*
 
7198
 *  Misc
 
7199
 */
 
7200
 
 
7201
struct duk_hstring {
 
7202
        /* smaller heaphdr than for other objects, because strings are held
 
7203
         * in string intern table which requires no link pointers.
 
7204
         */
 
7205
        duk_heaphdr_string hdr;
 
7206
 
 
7207
        /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
 
7208
         * shared heap header.  Good hashing needs more hash bits though.
 
7209
         */
 
7210
 
 
7211
        duk_uint32_t hash;         /* string hash */
 
7212
        duk_uint32_t blen;         /* length in bytes (not counting NUL term) */
 
7213
        duk_uint32_t clen;         /* length in codepoints (must be E5 compatible) */
 
7214
 
 
7215
        /*
 
7216
         *  String value of 'blen+1' bytes follows (+1 for NUL termination
 
7217
         *  convenience for C API).  No alignment needs to be guaranteed
 
7218
         *  for strings, but fields above should guarantee alignment-by-4
 
7219
         *  (but not alignment-by-8).
 
7220
         */
 
7221
};
 
7222
 
 
7223
/*
 
7224
 *  Prototypes
 
7225
 */
 
7226
 
 
7227
duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_int_t pos);
 
7228
 
 
7229
#endif  /* DUK_HSTRING_H_INCLUDED */
 
7230
 
 
7231
#line 1 "duk_hobject.h"
 
7232
/*
 
7233
 *  Heap object representation.
 
7234
 *
 
7235
 *  Heap objects are used for Ecmascript objects, arrays, and functions,
 
7236
 *  but also for internal control like declarative and object environment
 
7237
 *  records.  Compiled functions, native functions, and threads are also
 
7238
 *  objects but with an extended C struct.
 
7239
 *
 
7240
 *  Objects provide the required Ecmascript semantics and special behaviors
 
7241
 *  especially for property access.
 
7242
 *
 
7243
 *  Properties are stored in three conceptual parts:
 
7244
 *
 
7245
 *    1. A linear 'entry part' contains ordered key-value-attributes triples
 
7246
 *       and is the main method of string properties.
 
7247
 *
 
7248
 *    2. An optional linear 'array part' is used for array objects to store a
 
7249
 *       (dense) range of [0,N[ array indexed entries with default attributes
 
7250
 *       (writable, enumerable, configurable).  If the array part would become
 
7251
 *       sparse or non-default attributes are required, the array part is
 
7252
 *       abandoned and moved to the 'entry part'.
 
7253
 *
 
7254
 *    3. An optional 'hash part' is used to optimize lookups of the entry
 
7255
 *       part; it is used only for objects with sufficiently many properties 
 
7256
 *       and can be abandoned without loss of information.
 
7257
 *
 
7258
 *  These three conceptual parts are stored in a single memory allocated area.
 
7259
 *  This minimizes memory allocation overhead but also means that all three
 
7260
 *  parts are resized together, and makes property access a bit complicated.
 
7261
 */
 
7262
 
 
7263
#ifndef DUK_HOBJECT_H_INCLUDED
 
7264
#define DUK_HOBJECT_H_INCLUDED
 
7265
 
 
7266
/* there are currently 26 flag bits available */
 
7267
#define DUK_HOBJECT_FLAG_EXTENSIBLE            DUK_HEAPHDR_USER_FLAG(0)   /* object is extensible */
 
7268
#define DUK_HOBJECT_FLAG_CONSTRUCTABLE         DUK_HEAPHDR_USER_FLAG(1)   /* object is constructable */
 
7269
#define DUK_HOBJECT_FLAG_BOUND                 DUK_HEAPHDR_USER_FLAG(2)   /* object established using Function.prototype.bind() */
 
7270
#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION      DUK_HEAPHDR_USER_FLAG(4)   /* object is a compiled function (duk_hcompiledfunction) */
 
7271
#define DUK_HOBJECT_FLAG_NATIVEFUNCTION        DUK_HEAPHDR_USER_FLAG(5)   /* object is a native function (duk_hnativefunction) */
 
7272
#define DUK_HOBJECT_FLAG_THREAD                DUK_HEAPHDR_USER_FLAG(6)   /* object is a thread (duk_hthread) */
 
7273
#define DUK_HOBJECT_FLAG_ARRAY_PART            DUK_HEAPHDR_USER_FLAG(7)   /* object has an array part (a_size may still be 0) */
 
7274
#define DUK_HOBJECT_FLAG_STRICT                DUK_HEAPHDR_USER_FLAG(8)   /* function: function object is strict */
 
7275
#define DUK_HOBJECT_FLAG_NEWENV                DUK_HEAPHDR_USER_FLAG(9)   /* function: create new environment when called (see duk_hcompiledfunction) */
 
7276
#define DUK_HOBJECT_FLAG_NAMEBINDING           DUK_HEAPHDR_USER_FLAG(10)  /* function: create binding for func name (function templates only, used for named function expressions) */
 
7277
#define DUK_HOBJECT_FLAG_CREATEARGS            DUK_HEAPHDR_USER_FLAG(11)  /* function: create an arguments object on function call */
 
7278
#define DUK_HOBJECT_FLAG_ENVRECCLOSED          DUK_HEAPHDR_USER_FLAG(12)  /* envrec: (declarative) record is closed */
 
7279
#define DUK_HOBJECT_FLAG_SPECIAL_ARRAY         DUK_HEAPHDR_USER_FLAG(13)  /* 'Array' object, array length and index special behavior */
 
7280
#define DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ     DUK_HEAPHDR_USER_FLAG(14)  /* 'String' object, array index special behavior */
 
7281
#define DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS     DUK_HEAPHDR_USER_FLAG(15)  /* 'Arguments' object and has arguments special behavior (non-strict callee) */
 
7282
#define DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC       DUK_HEAPHDR_USER_FLAG(16)  /* Duktape/C (nativefunction) object, special 'length' */
 
7283
#define DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ     DUK_HEAPHDR_USER_FLAG(17)  /* 'Buffer' object, array index special behavior, virtual 'length' */
 
7284
/* bit 18 unused */
 
7285
/* bit 19 unused */
 
7286
/* bit 20 unused */
 
7287
 
 
7288
#define DUK_HOBJECT_FLAG_CLASS_BASE            DUK_HEAPHDR_USER_FLAG_NUMBER(21)
 
7289
#define DUK_HOBJECT_FLAG_CLASS_BITS            5
 
7290
 
 
7291
#define DUK_HOBJECT_GET_CLASS_NUMBER(h)        \
 
7292
        DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
 
7293
#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v)      \
 
7294
        DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
 
7295
 
 
7296
/* for creating flag initializers */
 
7297
#define DUK_HOBJECT_CLASS_AS_FLAGS(v)          ((v) << DUK_HOBJECT_FLAG_CLASS_BASE)
 
7298
 
 
7299
/* E5 Section 8.6.2 + custom classes */
 
7300
#define DUK_HOBJECT_CLASS_UNUSED               0
 
7301
#define DUK_HOBJECT_CLASS_ARGUMENTS            1
 
7302
#define DUK_HOBJECT_CLASS_ARRAY                2
 
7303
#define DUK_HOBJECT_CLASS_BOOLEAN              3
 
7304
#define DUK_HOBJECT_CLASS_DATE                 4
 
7305
#define DUK_HOBJECT_CLASS_ERROR                5
 
7306
#define DUK_HOBJECT_CLASS_FUNCTION             6
 
7307
#define DUK_HOBJECT_CLASS_JSON                 7
 
7308
#define DUK_HOBJECT_CLASS_MATH                 8
 
7309
#define DUK_HOBJECT_CLASS_NUMBER               9
 
7310
#define DUK_HOBJECT_CLASS_OBJECT               10
 
7311
#define DUK_HOBJECT_CLASS_REGEXP               11
 
7312
#define DUK_HOBJECT_CLASS_STRING               12
 
7313
#define DUK_HOBJECT_CLASS_GLOBAL               13
 
7314
#define DUK_HOBJECT_CLASS_OBJENV               14  /* custom */
 
7315
#define DUK_HOBJECT_CLASS_DECENV               15  /* custom */
 
7316
#define DUK_HOBJECT_CLASS_BUFFER               16  /* custom */
 
7317
#define DUK_HOBJECT_CLASS_POINTER              17  /* custom */
 
7318
#define DUK_HOBJECT_CLASS_THREAD               18  /* custom */
 
7319
 
 
7320
#define DUK_HOBJECT_IS_OBJENV(h)               (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
 
7321
#define DUK_HOBJECT_IS_DECENV(h)               (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
 
7322
#define DUK_HOBJECT_IS_ENV(h)                  (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
 
7323
#define DUK_HOBJECT_IS_ARRAY(h)                (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
 
7324
#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
 
7325
#define DUK_HOBJECT_IS_NATIVEFUNCTION(h)       DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7326
#define DUK_HOBJECT_IS_THREAD(h)               DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
 
7327
 
 
7328
#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
 
7329
                                                        DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
 
7330
                                                        DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7331
 
 
7332
#define DUK_HOBJECT_IS_FUNCTION(h)             DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
 
7333
                                                        DUK_HOBJECT_FLAG_BOUND | \
 
7334
                                                        DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
 
7335
                                                        DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7336
 
 
7337
#define DUK_HOBJECT_IS_CALLABLE(h)             DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
 
7338
                                                        DUK_HOBJECT_FLAG_BOUND | \
 
7339
                                                        DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
 
7340
                                                        DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7341
 
 
7342
/* object has any special behavior(s) */
 
7343
#define DUK_HOBJECT_SPECIAL_BEHAVIOR_FLAGS     (DUK_HOBJECT_FLAG_SPECIAL_ARRAY | \
 
7344
                                                DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS | \
 
7345
                                                DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ | \
 
7346
                                                DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC | \
 
7347
                                                DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
 
7348
 
 
7349
#define DUK_HOBJECT_HAS_SPECIAL_BEHAVIOR(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_SPECIAL_BEHAVIOR_FLAGS)
 
7350
 
 
7351
#define DUK_HOBJECT_HAS_EXTENSIBLE(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
 
7352
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h)       DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
 
7353
#define DUK_HOBJECT_HAS_BOUND(h)               DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
 
7354
#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
 
7355
#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h)      DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7356
#define DUK_HOBJECT_HAS_THREAD(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
 
7357
#define DUK_HOBJECT_HAS_ARRAY_PART(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
 
7358
#define DUK_HOBJECT_HAS_STRICT(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
 
7359
#define DUK_HOBJECT_HAS_NEWENV(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
 
7360
#define DUK_HOBJECT_HAS_NAMEBINDING(h)         DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
 
7361
#define DUK_HOBJECT_HAS_CREATEARGS(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
 
7362
#define DUK_HOBJECT_HAS_ENVRECCLOSED(h)        DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
 
7363
#define DUK_HOBJECT_HAS_SPECIAL_ARRAY(h)       DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARRAY)
 
7364
#define DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(h)   DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
 
7365
#define DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(h)   DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
 
7366
#define DUK_HOBJECT_HAS_SPECIAL_DUKFUNC(h)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
 
7367
#define DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(h)   DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
 
7368
 
 
7369
#define DUK_HOBJECT_SET_EXTENSIBLE(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
 
7370
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h)       DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
 
7371
#define DUK_HOBJECT_SET_BOUND(h)               DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
 
7372
#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h)    DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
 
7373
#define DUK_HOBJECT_SET_NATIVEFUNCTION(h)      DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7374
#define DUK_HOBJECT_SET_THREAD(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
 
7375
#define DUK_HOBJECT_SET_ARRAY_PART(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
 
7376
#define DUK_HOBJECT_SET_STRICT(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
 
7377
#define DUK_HOBJECT_SET_NEWENV(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
 
7378
#define DUK_HOBJECT_SET_NAMEBINDING(h)         DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
 
7379
#define DUK_HOBJECT_SET_CREATEARGS(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
 
7380
#define DUK_HOBJECT_SET_ENVRECCLOSED(h)        DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
 
7381
#define DUK_HOBJECT_SET_SPECIAL_ARRAY(h)       DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARRAY)
 
7382
#define DUK_HOBJECT_SET_SPECIAL_STRINGOBJ(h)   DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
 
7383
#define DUK_HOBJECT_SET_SPECIAL_ARGUMENTS(h)   DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
 
7384
#define DUK_HOBJECT_SET_SPECIAL_DUKFUNC(h)     DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
 
7385
#define DUK_HOBJECT_SET_SPECIAL_BUFFEROBJ(h)   DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
 
7386
 
 
7387
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
 
7388
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
 
7389
#define DUK_HOBJECT_CLEAR_BOUND(h)             DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
 
7390
#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
 
7391
#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
 
7392
#define DUK_HOBJECT_CLEAR_THREAD(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
 
7393
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
 
7394
#define DUK_HOBJECT_CLEAR_STRICT(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
 
7395
#define DUK_HOBJECT_CLEAR_NEWENV(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
 
7396
#define DUK_HOBJECT_CLEAR_NAMEBINDING(h)       DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
 
7397
#define DUK_HOBJECT_CLEAR_CREATEARGS(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
 
7398
#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h)      DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
 
7399
#define DUK_HOBJECT_CLEAR_SPECIAL_ARRAY(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARRAY)
 
7400
#define DUK_HOBJECT_CLEAR_SPECIAL_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ)
 
7401
#define DUK_HOBJECT_CLEAR_SPECIAL_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS)
 
7402
#define DUK_HOBJECT_CLEAR_SPECIAL_DUKFUNC(h)   DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC)
 
7403
#define DUK_HOBJECT_CLEAR_SPECIAL_BUFFEROBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ)
 
7404
 
 
7405
/* flags used for property attributes in duk_propdesc and packed flags */
 
7406
#define DUK_PROPDESC_FLAG_WRITABLE              (1 << 0)    /* E5 Section 8.6.1 */
 
7407
#define DUK_PROPDESC_FLAG_ENUMERABLE            (1 << 1)    /* E5 Section 8.6.1 */
 
7408
#define DUK_PROPDESC_FLAG_CONFIGURABLE          (1 << 2)    /* E5 Section 8.6.1 */
 
7409
#define DUK_PROPDESC_FLAG_ACCESSOR              (1 << 3)    /* accessor */
 
7410
#define DUK_PROPDESC_FLAG_VIRTUAL               (1 << 4)    /* property is virtual: used in duk_propdesc, never stored
 
7411
                                                             * (used by e.g. buffer virtual properties)
 
7412
                                                             */
 
7413
#define DUK_PROPDESC_FLAGS_MASK                 (DUK_PROPDESC_FLAG_WRITABLE | \
 
7414
                                                 DUK_PROPDESC_FLAG_ENUMERABLE | \
 
7415
                                                 DUK_PROPDESC_FLAG_CONFIGURABLE | \
 
7416
                                                 DUK_PROPDESC_FLAG_ACCESSOR)
 
7417
 
 
7418
/* additional flags which are passed in the same flags argument as property
 
7419
 * flags but are not stored in object properties.
 
7420
 */
 
7421
#define DUK_PROPDESC_FLAG_NO_OVERWRITE          (1 << 4)    /* internal define property: skip write silently if exists */
 
7422
 
 
7423
/* convenience */
 
7424
#define DUK_PROPDESC_FLAGS_NONE                 0
 
7425
#define DUK_PROPDESC_FLAGS_W                    (DUK_PROPDESC_FLAG_WRITABLE)
 
7426
#define DUK_PROPDESC_FLAGS_E                    (DUK_PROPDESC_FLAG_ENUMERABLE)
 
7427
#define DUK_PROPDESC_FLAGS_C                    (DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7428
#define DUK_PROPDESC_FLAGS_WE                   (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
 
7429
#define DUK_PROPDESC_FLAGS_WC                   (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7430
#define DUK_PROPDESC_FLAGS_EC                   (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7431
#define DUK_PROPDESC_FLAGS_WEC                  (DUK_PROPDESC_FLAG_WRITABLE | \
 
7432
                                                 DUK_PROPDESC_FLAG_ENUMERABLE | \
 
7433
                                                 DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7434
 
 
7435
/*
 
7436
 *  Macros to access the 'p' allocation.
 
7437
 */
 
7438
 
 
7439
#if defined(DUK_USE_HOBJECT_LAYOUT_1)
 
7440
/* LAYOUT 1 */
 
7441
#define DUK_HOBJECT_E_GET_KEY_BASE(h)           \
 
7442
        ((duk_hstring **) ( \
 
7443
                (h)->p \
 
7444
        ))
 
7445
#define DUK_HOBJECT_E_GET_VALUE_BASE(h)         \
 
7446
        ((duk_propvalue *) ( \
 
7447
                (h)->p + \
 
7448
                        (h)->e_size * sizeof(duk_hstring *) \
 
7449
        ))
 
7450
#define DUK_HOBJECT_E_GET_FLAGS_BASE(h)         \
 
7451
        ((duk_uint8_t *) ( \
 
7452
                (h)->p + (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
 
7453
        ))
 
7454
#define DUK_HOBJECT_A_GET_BASE(h)               \
 
7455
        ((duk_tval *) ( \
 
7456
                (h)->p + \
 
7457
                        (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
 
7458
        ))
 
7459
#define DUK_HOBJECT_H_GET_BASE(h)               \
 
7460
        ((duk_uint32_t *) ( \
 
7461
                (h)->p + \
 
7462
                        (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
 
7463
                        (h)->a_size * sizeof(duk_tval) \
 
7464
        ))
 
7465
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
 
7466
        ( \
 
7467
                (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
 
7468
                (n_arr) * sizeof(duk_tval) + \
 
7469
                (n_hash) * sizeof(duk_uint32_t) \
 
7470
        )
 
7471
#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 { \
 
7472
                (set_e_k) = (duk_hstring **) (p_base); \
 
7473
                (set_e_pv) = (duk_propvalue *) ((set_e_k) + (n_ent)); \
 
7474
                (set_e_f) = (duk_uint8_t *) ((set_e_pv) + (n_ent)); \
 
7475
                (set_a) = (duk_tval *) ((set_e_f) + (n_ent)); \
 
7476
                (set_h) = (duk_uint32_t *) ((set_a) + (n_arr)); \
 
7477
        } while (0)
 
7478
#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
 
7479
/* LAYOUT 2 */
 
7480
#if defined(DUK_USE_ALIGN_4)
 
7481
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
 
7482
#elif defined(DUK_USE_ALIGN_8)
 
7483
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
 
7484
#else
 
7485
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
 
7486
#endif
 
7487
#define DUK_HOBJECT_E_GET_KEY_BASE(h)           \
 
7488
        ((duk_hstring **) ( \
 
7489
                (h)->p + \
 
7490
                        (h)->e_size * sizeof(duk_propvalue) \
 
7491
        ))
 
7492
#define DUK_HOBJECT_E_GET_VALUE_BASE(h)         \
 
7493
        ((duk_propvalue *) ( \
 
7494
                (h)->p \
 
7495
        ))
 
7496
#define DUK_HOBJECT_E_GET_FLAGS_BASE(h)         \
 
7497
        ((duk_uint8_t *) ( \
 
7498
                (h)->p + (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
 
7499
        ))
 
7500
#define DUK_HOBJECT_A_GET_BASE(h)               \
 
7501
        ((duk_tval *) ( \
 
7502
                (h)->p + \
 
7503
                        (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
 
7504
                        DUK_HOBJECT_E_FLAG_PADDING((h)->e_size) \
 
7505
        ))
 
7506
#define DUK_HOBJECT_H_GET_BASE(h)               \
 
7507
        ((duk_uint32_t *) ( \
 
7508
                (h)->p + \
 
7509
                        (h)->e_size * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
 
7510
                        DUK_HOBJECT_E_FLAG_PADDING((h)->e_size) + \
 
7511
                        (h)->a_size * sizeof(duk_tval) \
 
7512
        ))
 
7513
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
 
7514
        ( \
 
7515
                (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
 
7516
                DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
 
7517
                (n_arr) * sizeof(duk_tval) + \
 
7518
                (n_hash) * sizeof(duk_uint32_t) \
 
7519
        )
 
7520
#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 { \
 
7521
                (set_e_pv) = (duk_propvalue *) (p_base); \
 
7522
                (set_e_k) = (duk_hstring **) ((set_e_pv) + (n_ent)); \
 
7523
                (set_e_f) = (duk_uint8_t *) ((set_e_k) + (n_ent)); \
 
7524
                (set_a) = (duk_tval *) (((duk_uint8_t *) (set_e_f)) + \
 
7525
                                        sizeof(duk_uint8_t) * (n_ent) + \
 
7526
                                        DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
 
7527
                (set_h) = (duk_uint32_t *) ((set_a) + (n_arr)); \
 
7528
        } while (0)
 
7529
#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
 
7530
/* LAYOUT 3 */
 
7531
#define DUK_HOBJECT_E_GET_KEY_BASE(h)           \
 
7532
        ((duk_hstring **) ( \
 
7533
                (h)->p + \
 
7534
                        (h)->e_size * sizeof(duk_propvalue) + \
 
7535
                        (h)->a_size * sizeof(duk_tval) \
 
7536
        ))
 
7537
#define DUK_HOBJECT_E_GET_VALUE_BASE(h)         \
 
7538
        ((duk_propvalue *) ( \
 
7539
                (h)->p \
 
7540
        ))
 
7541
#define DUK_HOBJECT_E_GET_FLAGS_BASE(h)         \
 
7542
        ((duk_uint8_t *) ( \
 
7543
                (h)->p + \
 
7544
                        (h)->e_size * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
 
7545
                        (h)->a_size * sizeof(duk_tval) + \
 
7546
                        (h)->h_size * sizeof(duk_uint32_t) \
 
7547
        ))
 
7548
#define DUK_HOBJECT_A_GET_BASE(h)               \
 
7549
        ((duk_tval *) ( \
 
7550
                (h)->p + \
 
7551
                        (h)->e_size * sizeof(duk_propvalue) \
 
7552
        ))
 
7553
#define DUK_HOBJECT_H_GET_BASE(h)               \
 
7554
        ((duk_uint32_t *) ( \
 
7555
                (h)->p + \
 
7556
                        (h)->e_size * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
 
7557
                        (h)->a_size * sizeof(duk_tval) \
 
7558
        ))
 
7559
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
 
7560
        ( \
 
7561
                (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
 
7562
                (n_arr) * sizeof(duk_tval) + \
 
7563
                (n_hash) * sizeof(duk_uint32_t) \
 
7564
        )
 
7565
#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 { \
 
7566
                (set_e_pv) = (duk_propvalue *) (p_base); \
 
7567
                (set_a) = (duk_tval *) ((set_e_pv) + (n_ent)); \
 
7568
                (set_e_k) = (duk_hstring **) ((set_a) + (n_arr)); \
 
7569
                (set_h) = (duk_uint32_t *) ((set_e_k) + (n_ent)); \
 
7570
                (set_e_f) = (duk_uint8_t *) ((set_h) + (n_hash)); \
 
7571
        } while (0)
 
7572
#else
 
7573
#error invalid hobject layout defines
 
7574
#endif  /* hobject property layout */
 
7575
 
 
7576
#define DUK_HOBJECT_E_ALLOC_SIZE(h) DUK_HOBJECT_P_COMPUTE_SIZE((h)->e_size, (h)->a_size, (h)->h_size)
 
7577
 
 
7578
#define DUK_HOBJECT_E_GET_KEY(h,i)              (DUK_HOBJECT_E_GET_KEY_BASE((h))[(i)])
 
7579
#define DUK_HOBJECT_E_GET_KEY_PTR(h,i)          (&DUK_HOBJECT_E_GET_KEY_BASE((h))[(i)])
 
7580
#define DUK_HOBJECT_E_GET_VALUE(h,i)            (DUK_HOBJECT_E_GET_VALUE_BASE((h))[(i)])
 
7581
#define DUK_HOBJECT_E_GET_VALUE_PTR(h,i)        (&DUK_HOBJECT_E_GET_VALUE_BASE((h))[(i)])
 
7582
#define DUK_HOBJECT_E_GET_VALUE_TVAL(h,i)       (DUK_HOBJECT_E_GET_VALUE((h),(i)).v)
 
7583
#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(h,i)   (&DUK_HOBJECT_E_GET_VALUE((h),(i)).v)
 
7584
#define DUK_HOBJECT_E_GET_VALUE_GETTER(h,i)     (DUK_HOBJECT_E_GET_VALUE((h),(i)).a.get)
 
7585
#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(h,i) (&DUK_HOBJECT_E_GET_VALUE((h),(i)).a.get)
 
7586
#define DUK_HOBJECT_E_GET_VALUE_SETTER(h,i)     (DUK_HOBJECT_E_GET_VALUE((h),(i)).a.set)
 
7587
#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(h,i) (&DUK_HOBJECT_E_GET_VALUE((h),(i)).a.set)
 
7588
#define DUK_HOBJECT_E_GET_FLAGS(h,i)            (DUK_HOBJECT_E_GET_FLAGS_BASE((h))[(i)])
 
7589
#define DUK_HOBJECT_E_GET_FLAGS_PTR(h,i)        (&DUK_HOBJECT_E_GET_FLAGS_BASE((h))[(i)])
 
7590
#define DUK_HOBJECT_A_GET_VALUE(h,i)            (DUK_HOBJECT_A_GET_BASE((h))[(i)])
 
7591
#define DUK_HOBJECT_A_GET_VALUE_PTR(h,i)        (&DUK_HOBJECT_A_GET_BASE((h))[(i)])
 
7592
#define DUK_HOBJECT_H_GET_INDEX(h,i)            (DUK_HOBJECT_H_GET_BASE((h))[(i)])
 
7593
#define DUK_HOBJECT_H_GET_INDEX_PTR(h,i)        (&DUK_HOBJECT_H_GET_BASE((h))[(i)])
 
7594
 
 
7595
#define DUK_HOBJECT_E_SET_KEY(h,i,k)  do { \
 
7596
                DUK_HOBJECT_E_GET_KEY((h),(i)) = (k); \
 
7597
        } while (0)
 
7598
#define DUK_HOBJECT_E_SET_VALUE(h,i,v)  do { \
 
7599
                DUK_HOBJECT_E_GET_VALUE((h),(i)) = (v); \
 
7600
        } while (0)
 
7601
#define DUK_HOBJECT_E_SET_VALUE_TVAL(h,i,v)  do { \
 
7602
                DUK_HOBJECT_E_GET_VALUE((h),(i)).v = (v); \
 
7603
        } while (0)
 
7604
#define DUK_HOBJECT_E_SET_VALUE_GETTER(h,i,v)  do { \
 
7605
                DUK_HOBJECT_E_GET_VALUE((h),(i)).a.get = (v); \
 
7606
        } while (0)
 
7607
#define DUK_HOBJECT_E_SET_VALUE_SETTER(h,i,v)  do { \
 
7608
                DUK_HOBJECT_E_GET_VALUE((h),(i)).a.set = (v); \
 
7609
        } while (0)
 
7610
#define DUK_HOBJECT_E_SET_FLAGS(h,i,f)  do { \
 
7611
                DUK_HOBJECT_E_GET_FLAGS((h),(i)) = (f); \
 
7612
        } while (0)
 
7613
#define DUK_HOBJECT_A_SET_VALUE(h,i,v)  do { \
 
7614
                DUK_HOBJECT_A_GET_VALUE((h),(i)) = (v); \
 
7615
        } while (0)
 
7616
#define DUK_HOBJECT_A_SET_VALUE_TVAL(h,i,v)  DUK_HOBJECT_A_SET_VALUE((h),(i),(v))  /* alias for above */
 
7617
#define DUK_HOBJECT_H_SET_INDEX(h,i,v)  do { \
 
7618
                DUK_HOBJECT_H_GET_INDEX((h),(i)) = (v); \
 
7619
        } while (0)
 
7620
 
 
7621
#define DUK_HOBJECT_E_SET_FLAG_BITS(h,i,mask)  do { \
 
7622
                DUK_HOBJECT_E_GET_FLAGS_BASE((h))[(i)] |= (mask); \
 
7623
        } while (0)
 
7624
 
 
7625
#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(h,i,mask)  do { \
 
7626
                DUK_HOBJECT_E_GET_FLAGS_BASE((h))[(i)] &= ~(mask); \
 
7627
        } while (0)
 
7628
 
 
7629
#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(h,i)     ((DUK_HOBJECT_E_GET_FLAGS((h),(i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
 
7630
#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(h,i)   ((DUK_HOBJECT_E_GET_FLAGS((h),(i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
 
7631
#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(h,i) ((DUK_HOBJECT_E_GET_FLAGS((h),(i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
 
7632
#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h,i)     ((DUK_HOBJECT_E_GET_FLAGS((h),(i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
 
7633
 
 
7634
#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(h,i)        DUK_HOBJECT_E_SET_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_WRITABLE)
 
7635
#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(h,i)      DUK_HOBJECT_E_SET_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_ENUMERABLE)
 
7636
#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(h,i)    DUK_HOBJECT_E_SET_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7637
#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(h,i)        DUK_HOBJECT_E_SET_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_ACCESSOR)
 
7638
 
 
7639
#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(h,i)      DUK_HOBJECT_E_CLEAR_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_WRITABLE)
 
7640
#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(h,i)    DUK_HOBJECT_E_CLEAR_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_ENUMERABLE)
 
7641
#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(h,i)  DUK_HOBJECT_E_CLEAR_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_CONFIGURABLE)
 
7642
#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(h,i)      DUK_HOBJECT_E_CLEAR_FLAG_BITS((h),(i),DUK_PROPDESC_FLAG_ACCESSOR)
 
7643
 
 
7644
#define DUK_PROPDESC_IS_WRITABLE(p)             (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
 
7645
#define DUK_PROPDESC_IS_ENUMERABLE(p)           (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
 
7646
#define DUK_PROPDESC_IS_CONFIGURABLE(p)         (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
 
7647
#define DUK_PROPDESC_IS_ACCESSOR(p)             (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
 
7648
 
 
7649
#define DUK_HOBJECT_HASHIDX_UNUSED              0xffffffffUL
 
7650
#define DUK_HOBJECT_HASHIDX_DELETED             0xfffffffeUL
 
7651
 
 
7652
/*
 
7653
 *  Misc
 
7654
 */
 
7655
 
 
7656
/* Maximum prototype traversal depth.  Sanity limit which handles e.g.
 
7657
 * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
 
7658
 */
 
7659
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY      10000L
 
7660
 
 
7661
/* Maximum traversal depth for "bound function" chains. */
 
7662
#define DUK_HOBJECT_BOUND_CHAIN_SANITY          10000L
 
7663
 
 
7664
/*
 
7665
 *  Ecmascript [[Class]]
 
7666
 */
 
7667
 
 
7668
/* range check not necessary because all 4-bit values are mapped */
 
7669
#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n)  duk_class_number_to_stridx[(n)]
 
7670
 
 
7671
#define DUK_HOBJECT_GET_CLASS_STRING(heap,h)          \
 
7672
        DUK_HEAP_GET_STRING( \
 
7673
                (heap), \
 
7674
                DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
 
7675
        )
 
7676
 
 
7677
/*
 
7678
 *  Macros for property handling
 
7679
 */             
 
7680
 
 
7681
/* note: this updates refcounts */
 
7682
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p)       duk_hobject_set_prototype((thr),(h),(p))
 
7683
 
 
7684
/*
 
7685
 *  Macros for Ecmascript built-in semantics
 
7686
 */
 
7687
 
 
7688
#define DUK_HOBJECT_OBJECT_SEAL(thr,obj)                duk_hobject_object_seal_freeze_helper((thr),(obj),0)
 
7689
#define DUK_HOBJECT_OBJECT_FREEZE(htr,obj)              duk_hobject_object_seal_freeze_helper((thr),(obj),1)
 
7690
#define DUK_HOBJECT_OBJECT_IS_SEALED(obj)               duk_hobject_object_is_sealed_frozen_helper((obj),0)
 
7691
#define DUK_HOBJECT_OBJECT_IS_FROZEN(obj)               duk_hobject_object_is_sealed_frozen_helper((obj),1)
 
7692
#define DUK_HOBJECT_OBJECT_PREVENT_EXTENSIONS(vm,obj)   DUK_HOBJECT_CLEAR_EXTENSIBLE((obj))
 
7693
#define DUK_HOBJECT_OBJECT_IS_EXTENSIBLE(vm,obj)        DUK_HOBJECT_HAS_EXTENSIBLE((obj))
 
7694
 
 
7695
/*
 
7696
 *  Resizing and hash behavior
 
7697
 */
 
7698
 
 
7699
/* Sanity limit on max number of properties (allocated, not necessarily used).
 
7700
 * This is somewhat arbitrary, but if we're close to 2**32 properties some
 
7701
 * algorithms will fail (e.g. hash size selection, next prime selection).
 
7702
 * Also, we use negative array/entry table indices to indicate 'not found',
 
7703
 * so anything above 0x80000000 will cause trouble now.
 
7704
 */
 
7705
#define DUK_HOBJECT_MAX_PROPERTIES       0x7fffffffU   /* 2**31-1 ~= 2G properties */
 
7706
 
 
7707
/* higher value conserves memory; also note that linear scan is cache friendly */
 
7708
#define DUK_HOBJECT_E_USE_HASH_LIMIT     32
 
7709
 
 
7710
/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
 
7711
#define DUK_HOBJECT_H_SIZE_DIVISOR       4  /* hash size approx. 1.25 times entries size */
 
7712
 
 
7713
/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
 
7714
#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT  9  /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
 
7715
 
 
7716
/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
 
7717
/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
 
7718
#define DUK_HOBJECT_A_ABANDON_LIMIT      2  /* 25%, i.e. less than 25% used -> abandon */
 
7719
 
 
7720
/* internal align target for props allocation, must be 2*n for some n */
 
7721
#if defined(DUK_USE_ALIGN_4)
 
7722
#define DUK_HOBJECT_ALIGN_TARGET         4
 
7723
#elif defined(DUK_USE_ALIGN_8)
 
7724
#define DUK_HOBJECT_ALIGN_TARGET         8
 
7725
#else
 
7726
#define DUK_HOBJECT_ALIGN_TARGET         1
 
7727
#endif
 
7728
 
 
7729
/* controls for minimum entry part growth */
 
7730
#define DUK_HOBJECT_E_MIN_GROW_ADD       16
 
7731
#define DUK_HOBJECT_E_MIN_GROW_DIVISOR   8  /* 2^3 -> 1/8 = 12.5% min growth */
 
7732
 
 
7733
/* controls for minimum array part growth */
 
7734
#define DUK_HOBJECT_A_MIN_GROW_ADD       16
 
7735
#define DUK_HOBJECT_A_MIN_GROW_DIVISOR   8  /* 2^3 -> 1/8 = 12.5% min growth */
 
7736
 
 
7737
/* probe sequence */
 
7738
#define DUK_HOBJECT_HASH_INITIAL(hash,h_size)  ((hash) % (h_size))
 
7739
#define DUK_HOBJECT_HASH_PROBE_STEP(hash)      DUK_UTIL_GET_HASH_PROBE_STEP((hash))
 
7740
 
 
7741
/*
 
7742
 *  PC-to-line constants
 
7743
 */
 
7744
 
 
7745
#define DUK_PC2LINE_SKIP    64
 
7746
 
 
7747
/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
 
7748
#define DUK_PC2LINE_MAX_DIFF_LENGTH    (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
 
7749
 
 
7750
/*
 
7751
 *  Struct defs
 
7752
 */
 
7753
 
 
7754
struct duk_propaccessor {
 
7755
        duk_hobject *get;
 
7756
        duk_hobject *set;
 
7757
};
 
7758
 
 
7759
union duk_propvalue {
 
7760
        duk_tval v;
 
7761
        duk_propaccessor a;
 
7762
};
 
7763
 
 
7764
struct duk_propdesc {
 
7765
        /* read-only values 'lifted' for ease of use */
 
7766
        int flags;
 
7767
        duk_hobject *get;
 
7768
        duk_hobject *set;
 
7769
 
 
7770
        /* for updating (all are set to < 0 for virtual properties) */
 
7771
        int e_idx;      /* prop index in 'entry part', < 0 if not there */
 
7772
        int h_idx;      /* prop index in 'hash part', < 0 if not there */
 
7773
        int a_idx;      /* prop index in 'array part', < 0 if not there */
 
7774
};
 
7775
 
 
7776
struct duk_hobject {
 
7777
        duk_heaphdr hdr;
 
7778
 
 
7779
        /*
 
7780
         *  'p' contains {key,value,flags} entries, optional array entries, and an
 
7781
         *  optional hash lookup table for non-array entries in a single 'sliced'
 
7782
         *  allocation.  There are several layout options, which differ slightly in
 
7783
         *  generated code size/speed and alignment/padding; duk_features.h selects
 
7784
         *  the layout used.
 
7785
         *
 
7786
         *  Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
 
7787
         *
 
7788
         *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_used gc reachable)
 
7789
         *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_used gc reachable)
 
7790
         *    e_size * sizeof(duk_uint8_t)           bytes of   entry flags (e_used gc reachable)
 
7791
         *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
 
7792
         *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
 
7793
         *                                                      0xffffffffU = unused, 0xfffffffeU = deleted
 
7794
         *
 
7795
         *  Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
 
7796
         *
 
7797
         *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_used gc reachable)
 
7798
         *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_used gc reachable)
 
7799
         *    e_size * sizeof(duk_uint8_t) + pad     bytes of   entry flags (e_used gc reachable)
 
7800
         *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
 
7801
         *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
 
7802
         *                                                      0xffffffffU = unused, 0xfffffffeU = deleted
 
7803
         *
 
7804
         *  Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
 
7805
         *
 
7806
         *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_used gc reachable)
 
7807
         *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
 
7808
         *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_used gc reachable)
 
7809
         *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
 
7810
         *                                                      0xffffffffU = unused, 0xfffffffeU = deleted
 
7811
         *    e_size * sizeof(duk_uint8_t)           bytes of   entry flags (e_used gc reachable)
 
7812
         *
 
7813
         *  In layout 1, the 'e_used' count is rounded to 4 or 8 on platforms
 
7814
         *  requiring 4 or 8 byte alignment.  This ensures proper alignment
 
7815
         *  for the entries, at the cost of memory footprint.  However, it's
 
7816
         *  probably preferable to use another layout on such platforms instead.
 
7817
         *
 
7818
         *  In layout 2, the key and value parts are swapped to avoid padding
 
7819
         *  the key array on platforms requiring alignment by 8.  The flags part
 
7820
         *  is padded to get alignment for array entries.  The 'e_used' count does
 
7821
         *  not need to be rounded as in layout 1.
 
7822
         *
 
7823
         *  In layout 3, entry values and array values are always aligned properly,
 
7824
         *  and assuming pointers are at most 8 bytes, so are the entry keys.  Hash
 
7825
         *  indices will be properly aligned (assuming pointers are at least 4 bytes).
 
7826
         *  Finally, flags don't need additional alignment.  This layout provides
 
7827
         *  compact allocations without padding (even on platforms with alignment
 
7828
         *  requirements) at the cost of a bit slower lookups.
 
7829
         *
 
7830
         *  Objects with few keys don't have a hash index; keys are looked up linearly,
 
7831
         *  which is cache efficient because the keys are consecutive.  Larger objects
 
7832
         *  have a hash index part which contains integer indexes to the entries part.
 
7833
         *
 
7834
         *  A single allocation reduces memory allocation overhead but requires more
 
7835
         *  work when any part needs to be resized.  A sliced allocation for entries
 
7836
         *  makes linear key matching faster on most platforms (more locality) and
 
7837
         *  skimps on flags size (which would be followed by 3 bytes of padding in
 
7838
         *  most architectures if entries were placed in a struct).
 
7839
         *
 
7840
         *  'p' also contains internal properties distinguished with a non-BMP
 
7841
         *  prefix.  Often used properties should be placed early in 'p' whenever
 
7842
         *  possible to make accessing them as fast a possible.
 
7843
         */
 
7844
 
 
7845
        duk_uint8_t *p;
 
7846
        duk_uint32_t e_size;
 
7847
        duk_uint32_t e_used;
 
7848
        duk_uint32_t a_size;
 
7849
        duk_uint32_t h_size;
 
7850
 
 
7851
        /* prototype: the only internal property lifted outside 'e' as it is so central */
 
7852
        duk_hobject *prototype;
 
7853
};
 
7854
 
 
7855
/*
 
7856
 *  Exposed data
 
7857
 */
 
7858
 
 
7859
extern duk_uint8_t duk_class_number_to_stridx[32];
 
7860
 
 
7861
/*
 
7862
 *  Prototypes
 
7863
 */
 
7864
 
 
7865
/* alloc and init */
 
7866
duk_hobject *duk_hobject_alloc(duk_heap *heap, int hobject_flags);
 
7867
duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, int hobject_flags);
 
7868
duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, int hobject_flags);
 
7869
duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, int hobject_flags);
 
7870
duk_hthread *duk_hthread_alloc(duk_heap *heap, int hobject_flags);
 
7871
 
 
7872
/* low-level property functions */
 
7873
void duk_hobject_find_existing_entry(duk_hobject *obj, duk_hstring *key, int *e_idx, int *h_idx);
 
7874
duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_hobject *obj, duk_hstring *key);
 
7875
duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
 
7876
duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_hobject *obj, duk_uint32_t i);
 
7877
 
 
7878
/* core property functions */
 
7879
int duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
 
7880
int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, int throw_flag);
 
7881
int duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, int throw_flag);
 
7882
int duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
 
7883
 
 
7884
/* internal property functions */
 
7885
int duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, int throw_flag);
 
7886
int duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
 
7887
void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_int_t flags);
 
7888
void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uint32_t arr_idx, duk_small_int_t flags);
 
7889
void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_int_t propflags);
 
7890
void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length);
 
7891
void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
 
7892
duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
 
7893
 
 
7894
/* Object built-in methods */
 
7895
int duk_hobject_object_define_property(duk_context *ctx);
 
7896
int duk_hobject_object_define_properties(duk_context *ctx);
 
7897
int duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
 
7898
void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, int freeze);
 
7899
int duk_hobject_object_is_sealed_frozen_helper(duk_hobject *obj, int is_frozen);
 
7900
int duk_hobject_object_ownprop_helper(duk_context *ctx, int required_desc_flags);
 
7901
 
 
7902
/* internal properties */
 
7903
int duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
 
7904
duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
 
7905
duk_hbuffer *duk_hobject_get_internal_value_buffer(duk_heap *heap, duk_hobject *obj);
 
7906
        
 
7907
/* hobject management functions */
 
7908
void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
 
7909
 
 
7910
/* enumeration */
 
7911
void duk_hobject_enumerator_create(duk_context *ctx, int enum_flags);
 
7912
int duk_hobject_get_enumerated_keys(duk_context *ctx, int enum_flags);
 
7913
int duk_hobject_enumerator_next(duk_context *ctx, int get_value);
 
7914
 
 
7915
/* macros */
 
7916
void duk_hobject_set_prototype(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
 
7917
 
 
7918
/* finalization */
 
7919
void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
 
7920
 
 
7921
/* pc2line */
 
7922
#if defined(DUK_USE_PC2LINE)
 
7923
void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
 
7924
duk_uint_fast32_t duk_hobject_pc2line_query(duk_hbuffer_fixed *buf, duk_uint_fast32_t pc);
 
7925
#endif
 
7926
 
 
7927
/* misc */      
 
7928
int duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
 
7929
 
 
7930
#endif  /* DUK_HOBJECT_H_INCLUDED */
 
7931
 
 
7932
#line 1 "duk_hcompiledfunction.h"
 
7933
/*
 
7934
 *  Heap compiled function (Ecmascript function) representation.
 
7935
 *
 
7936
 *  There is a single data buffer containing the Ecmascript function's
 
7937
 *  bytecode, constants, and inner functions.
 
7938
 */
 
7939
 
 
7940
#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
 
7941
#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
 
7942
 
 
7943
/*
 
7944
 *  Accessor macros for function specific data areas
 
7945
 */
 
7946
 
 
7947
/* Note: assumes 'data' is always a fixed buffer */
 
7948
#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(h)  \
 
7949
        DUK_HBUFFER_FIXED_GET_DATA_PTR((duk_hbuffer_fixed *) (h)->data)
 
7950
 
 
7951
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(h)  \
 
7952
        ((duk_tval *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((h)))
 
7953
 
 
7954
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(h)  \
 
7955
        ((h)->funcs)
 
7956
 
 
7957
#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(h)  \
 
7958
        ((h)->bytecode)
 
7959
 
 
7960
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(h)  \
 
7961
        ((duk_tval *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((h)))
 
7962
 
 
7963
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(h)  \
 
7964
        ((duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((h)))
 
7965
 
 
7966
#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(h)  \
 
7967
        ((duk_instr *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((duk_hbuffer_fixed *) (h)->data) + \
 
7968
                        DUK_HBUFFER_GET_SIZE((h)->data)))
 
7969
 
 
7970
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(h)  \
 
7971
        ( \
 
7972
         (size_t) \
 
7973
         ( \
 
7974
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((h))) - \
 
7975
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((h))) \
 
7976
         ) \
 
7977
        )
 
7978
 
 
7979
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(h)  \
 
7980
        ( \
 
7981
         (size_t) \
 
7982
         ( \
 
7983
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((h))) - \
 
7984
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((h))) \
 
7985
         ) \
 
7986
        )
 
7987
 
 
7988
#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(h)  \
 
7989
        ( \
 
7990
         (size_t) \
 
7991
         ( \
 
7992
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((h))) - \
 
7993
           ((duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((h))) \
 
7994
         ) \
 
7995
        )
 
7996
 
 
7997
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(h)  \
 
7998
        ((size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((h)) / sizeof(duk_tval)))
 
7999
 
 
8000
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(h)  \
 
8001
        ((size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((h)) / sizeof(duk_hobject *)))
 
8002
 
 
8003
#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(h)  \
 
8004
        ((size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((h)) / sizeof(duk_instr)))
 
8005
 
 
8006
 
 
8007
/*
 
8008
 *  Main struct
 
8009
 */
 
8010
 
 
8011
struct duk_hcompiledfunction {
 
8012
        /* shared object part */
 
8013
        duk_hobject obj;
 
8014
 
 
8015
        /*
 
8016
         *  Pointers to function data area for faster access.  Function
 
8017
         *  data is a buffer shared between all closures of the same
 
8018
         *  "template" function.  The data buffer is always fixed (non-
 
8019
         *  dynamic, hence stable), with a layout as follows:
 
8020
         *
 
8021
         *    constants (duk_tval)
 
8022
         *    inner functions (duk_hobject *)
 
8023
         *    bytecode (duk_instr)
 
8024
         *
 
8025
         *  Note: bytecode end address can be computed from 'data' buffer
 
8026
         *  size.  It is not strictly necessary functionally, assuming
 
8027
         *  bytecode never jumps outside its allocated area.  However,
 
8028
         *  it's a safety/robustness feature for avoiding the chance of
 
8029
         *  executing random data as bytecode due to a compiler error.
 
8030
         *
 
8031
         *  Note: values in the data buffer must be incref'd (they will
 
8032
         *  be decref'd on release) for every compiledfunction referring
 
8033
         *  to the 'data' element.
 
8034
         */
 
8035
 
 
8036
        duk_hbuffer *data;    /* data area, fixed allocation, stable data ptrs */
 
8037
 
 
8038
        /* no need for constants pointer */
 
8039
        duk_hobject **funcs;
 
8040
        duk_instr *bytecode;
 
8041
 
 
8042
        /*
 
8043
         *  'nregs' registers are allocated on function entry, at most 'nargs'
 
8044
         *  are initialized to arguments, and the rest to undefined.  Arguments
 
8045
         *  above 'nregs' are not mapped to registers.  All registers in the
 
8046
         *  active stack range must be initialized because they are GC reachable.
 
8047
         *  'nargs' is needed so that if the function is given more than 'nargs'
 
8048
         *  arguments, the additional arguments do not 'clobber' registers
 
8049
         *  beyond 'nregs' which must be consistently initialized to undefined.
 
8050
         *
 
8051
         *  Usually there is no need to know which registers are mapped to
 
8052
         *  local variables.  Registers may be allocated to variable in any
 
8053
         *  way (even including gaps).  However, a register-variable mapping
 
8054
         *  must be the same for the duration of the function execution and
 
8055
         *  the register cannot be used for anything else.
 
8056
         *
 
8057
         *  When looking up variables by name, the '_varmap' map is used.
 
8058
         *  When an activation closes, registers mapped to arguments are
 
8059
         *  copied into the environment record based on the same map.  The
 
8060
         *  reverse map (from register to variable) is not currently needed
 
8061
         *  at run time, except for debugging, so it is not maintained.
 
8062
         */
 
8063
 
 
8064
        duk_uint16_t nregs;                /* regs to allocate */
 
8065
        duk_uint16_t nargs;                /* number of arguments allocated to regs */
 
8066
 
 
8067
        /*
 
8068
         *  Additional control information is placed into the object itself
 
8069
         *  as internal properties to avoid unnecessary fields for the
 
8070
         *  majority of functions.  The compiler tries to omit internal
 
8071
         *  control fields when possible.
 
8072
         *
 
8073
         *  Function templates:
 
8074
         *
 
8075
         *    {
 
8076
         *      _varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
 
8077
         *      _formals: [ "arg1", "arg2" ],
 
8078
         *      _name: "func",    // declaration, named function expressions
 
8079
         *      _source: "function func(arg1, arg2) { ... }",
 
8080
         *      _pc2line: <debug info for pc-to-line mapping>,
 
8081
         *      _filename: <debug info for creating nice errors>
 
8082
         *    }
 
8083
         *
 
8084
         *  Function instances:
 
8085
         *
 
8086
         *    {
 
8087
         *      length: 2,
 
8088
         *      prototype: { constructor: <func> },
 
8089
         *      caller: <thrower>,
 
8090
         *      arguments: <thrower>,
 
8091
         *      _varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
 
8092
         *      _formals: [ "arg1", "arg2" ],
 
8093
         *      _name: "func",    // declaration, named function expressions
 
8094
         *      _source: "function func(arg1, arg2) { ... }",
 
8095
         *      _pc2line: <debug info for pc-to-line mapping>,
 
8096
         *      _filename: <debug info for creating nice errors>
 
8097
         *      _varenv: <variable environment of closure>,
 
8098
         *      _lexenv: <lexical environment of closure (if differs from _varenv)>
 
8099
         *    }
 
8100
         *
 
8101
         *  More detailed description of these properties can be found
 
8102
         *  in the documentation.
 
8103
         */
 
8104
};
 
8105
 
 
8106
#endif  /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
 
8107
 
 
8108
#line 1 "duk_hnativefunction.h"
 
8109
/*
 
8110
 *  Heap native function representation.
 
8111
 */
 
8112
 
 
8113
#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
 
8114
#define DUK_HNATIVEFUNCTION_H_INCLUDED
 
8115
 
 
8116
#define DUK_HNATIVEFUNCTION_NARGS_VARARGS  ((duk_int16_t) -1)
 
8117
#define DUK_HNATIVEFUNCTION_NARGS_MAX      ((duk_int16_t) 0x7fff)
 
8118
 
 
8119
struct duk_hnativefunction {
 
8120
        /* shared object part */
 
8121
        duk_hobject obj;
 
8122
 
 
8123
        duk_c_function func;
 
8124
        duk_int16_t nargs;
 
8125
        duk_int16_t magic;
 
8126
 
 
8127
        /* The 'magic' field allows an opaque 16-bit field to be accessed by the
 
8128
         * Duktape/C function.  This allows, for instance, the same native function
 
8129
         * to be used for a set of very similar functions, with the 'magic' field
 
8130
         * providing the necessary non-argument flags / values to guide the behavior
 
8131
         * of the native function.  The value is signed on purpose: it is easier to
 
8132
         * convert a signed value to unsigned (simply AND with 0xffff) than vice
 
8133
         * versa.
 
8134
         *
 
8135
         * Note: cannot place nargs/magic into the heaphdr flags, because
 
8136
         * duk_hobject takes almost all flags already (and needs the spare).
 
8137
         */
 
8138
};
 
8139
 
 
8140
#endif  /* DUK_HNATIVEFUNCTION_H_INCLUDED */
 
8141
 
 
8142
#line 1 "duk_hthread.h"
 
8143
/*
 
8144
 *  Heap thread object representation.
 
8145
 *
 
8146
 *  duk_hthread is also the 'context' (duk_context) for exposed APIs
 
8147
 *  which mostly operate on the topmost frame of the value stack.
 
8148
 */
 
8149
 
 
8150
#ifndef DUK_HTHREAD_H_INCLUDED
 
8151
#define DUK_HTHREAD_H_INCLUDED
 
8152
 
 
8153
/*
 
8154
 *  Stack constants
 
8155
 */
 
8156
 
 
8157
#define DUK_VALSTACK_GROW_STEP          128     /* roughly 1 kiB */
 
8158
#define DUK_VALSTACK_SHRINK_THRESHOLD   256     /* roughly 2 kiB */
 
8159
#define DUK_VALSTACK_SHRINK_SPARE       64      /* roughly 0.5 kiB */
 
8160
#define DUK_VALSTACK_INITIAL_SIZE       128     /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
 
8161
#define DUK_VALSTACK_INTERNAL_EXTRA     64      /* internal extra elements assumed on function entry,
 
8162
                                                 * always added to user-defined 'extra' for e.g. the
 
8163
                                                 * duk_check_stack() call.
 
8164
                                                 */
 
8165
#define DUK_VALSTACK_API_ENTRY_MINIMUM  DUK_API_ENTRY_STACK
 
8166
                                                /* number of elements guaranteed to be user accessible
 
8167
                                                 * (in addition to call arguments) on Duktape/C function entry.
 
8168
                                                 */
 
8169
 
 
8170
/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
 
8171
 * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
 
8172
 * requirements.
 
8173
 */
 
8174
 
 
8175
#define DUK_VALSTACK_DEFAULT_MAX        1000000
 
8176
 
 
8177
#define DUK_CALLSTACK_GROW_STEP         8       /* roughly 256 bytes */
 
8178
#define DUK_CALLSTACK_SHRINK_THRESHOLD  16      /* roughly 512 bytes */
 
8179
#define DUK_CALLSTACK_SHRINK_SPARE      8       /* roughly 256 bytes */
 
8180
#define DUK_CALLSTACK_INITIAL_SIZE      8
 
8181
#define DUK_CALLSTACK_DEFAULT_MAX       10000
 
8182
 
 
8183
#define DUK_CATCHSTACK_GROW_STEP         4      /* roughly 64 bytes */
 
8184
#define DUK_CATCHSTACK_SHRINK_THRESHOLD  8      /* roughly 128 bytes */
 
8185
#define DUK_CATCHSTACK_SHRINK_SPARE      4      /* roughly 64 bytes */
 
8186
#define DUK_CATCHSTACK_INITIAL_SIZE      4
 
8187
#define DUK_CATCHSTACK_DEFAULT_MAX       10000
 
8188
 
 
8189
/*
 
8190
 *  Activation defines
 
8191
 */
 
8192
 
 
8193
#define DUK_ACT_FLAG_STRICT          (1 << 0)  /* function executes in strict mode */
 
8194
#define DUK_ACT_FLAG_TAILCALLED      (1 << 1)  /* activation has tailcalled one or more times */
 
8195
#define DUK_ACT_FLAG_CONSTRUCT       (1 << 2)  /* function executes as a constructor (called via "new") */
 
8196
#define DUK_ACT_FLAG_PREVENT_YIELD   (1 << 3)  /* activation prevents yield (native call or "new") */
 
8197
#define DUK_ACT_FLAG_DIRECT_EVAL     (1 << 4)  /* activation is a direct eval call */
 
8198
 
 
8199
/*
 
8200
 *  Flags for __FILE__ / __LINE__ registered into tracedata
 
8201
 */
 
8202
 
 
8203
#define DUK_TB_FLAG_NOBLAME_FILELINE   (1 << 0)  /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
 
8204
 
 
8205
/*
 
8206
 *  Catcher defines
 
8207
 */
 
8208
 
 
8209
/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
 
8210
#define DUK_CAT_TYPE_MASK            0x0000000fUL
 
8211
#define DUK_CAT_TYPE_BITS            4
 
8212
#define DUK_CAT_LABEL_MASK           0xffffff00UL
 
8213
#define DUK_CAT_LABEL_BITS           24
 
8214
#define DUK_CAT_LABEL_SHIFT          8
 
8215
 
 
8216
#define DUK_CAT_FLAG_CATCH_ENABLED          (1 << 4)   /* catch part will catch */
 
8217
#define DUK_CAT_FLAG_FINALLY_ENABLED        (1 << 5)   /* finally part will catch */
 
8218
#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED  (1 << 6)   /* request to create catch binding */
 
8219
#define DUK_CAT_FLAG_LEXENV_ACTIVE          (1 << 7)   /* catch or with binding is currently active */
 
8220
 
 
8221
#define DUK_CAT_TYPE_UNKNOWN         0
 
8222
#define DUK_CAT_TYPE_TCF             1
 
8223
#define DUK_CAT_TYPE_LABEL           2
 
8224
 
 
8225
#define DUK_CAT_GET_TYPE(c)          ((c)->flags & DUK_CAT_TYPE_MASK)
 
8226
#define DUK_CAT_GET_LABEL(c)         (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
 
8227
 
 
8228
#define DUK_CAT_HAS_CATCH_ENABLED(c)           ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
 
8229
#define DUK_CAT_HAS_FINALLY_ENABLED(c)         ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
 
8230
#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c)   ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
 
8231
#define DUK_CAT_HAS_LEXENV_ACTIVE(c)           ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
 
8232
 
 
8233
#define DUK_CAT_SET_CATCH_ENABLED(c)    do { \
 
8234
                (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
 
8235
        } while (0)
 
8236
#define DUK_CAT_SET_FINALLY_ENABLED(c)  do { \
 
8237
                (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
 
8238
        } while (0)
 
8239
#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c)    do { \
 
8240
                (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
 
8241
        } while (0)
 
8242
#define DUK_CAT_SET_LEXENV_ACTIVE(c)    do { \
 
8243
                (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
 
8244
        } while (0)
 
8245
 
 
8246
#define DUK_CAT_CLEAR_CATCH_ENABLED(c)    do { \
 
8247
                (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
 
8248
        } while (0)
 
8249
#define DUK_CAT_CLEAR_FINALLY_ENABLED(c)  do { \
 
8250
                (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
 
8251
        } while (0)
 
8252
#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c)    do { \
 
8253
                (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
 
8254
        } while (0)
 
8255
#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c)    do { \
 
8256
                (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
 
8257
        } while (0)
 
8258
 
 
8259
/*
 
8260
 *  Thread defines
 
8261
 */
 
8262
 
 
8263
#define DUK_HTHREAD_GET_STRING(thr,idx)          ((thr)->strs[(idx)])
 
8264
 
 
8265
#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr)  (&(thr)->callstack[(thr)->callstack_top - 1])
 
8266
 
 
8267
/* values for the state field */
 
8268
#define DUK_HTHREAD_STATE_INACTIVE     1   /* thread not currently running */
 
8269
#define DUK_HTHREAD_STATE_RUNNING      2   /* thread currently running (only one at a time) */
 
8270
#define DUK_HTHREAD_STATE_RESUMED      3   /* thread resumed another thread (active but not running) */
 
8271
#define DUK_HTHREAD_STATE_YIELDED      4   /* thread has yielded */
 
8272
#define DUK_HTHREAD_STATE_TERMINATED   5   /* thread has terminated */
 
8273
 
 
8274
/*
 
8275
 *  Struct defines
 
8276
 */
 
8277
 
 
8278
/* Note: it's nice if size is 2^N (now 32 bytes on 32 bit) */
 
8279
struct duk_activation {
 
8280
        duk_hobject *func;      /* function being executed; for bound function calls, this is the final, real function */
 
8281
        duk_hobject *var_env;   /* current variable environment (may be NULL if delayed) */
 
8282
        duk_hobject *lex_env;   /* current lexical environment (may be NULL if delayed) */
 
8283
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
8284
        /* Previous value of 'func' caller, restored when unwound.  Only in use
 
8285
         * when 'func' is non-strict.
 
8286
         */
 
8287
        duk_hobject *prev_caller;
 
8288
#endif
 
8289
 
 
8290
        int flags;
 
8291
        int pc;                 /* next instruction to execute */
 
8292
 
 
8293
        /* These following are only used for book-keeping of Ecmascript-initiated
 
8294
         * calls, to allow returning to an Ecmascript function properly.
 
8295
         *
 
8296
         * Note: idx_bottom is always set, while idx_retval is only applicable for
 
8297
         * activations below the topmost one.  Currently idx_retval for the topmost
 
8298
         * activation is considered garbage (and it not initialized on entry or
 
8299
         * cleared on return; may contain previous or garbage values).
 
8300
         */
 
8301
 
 
8302
        int idx_bottom;         /* Bottom of valstack for this activation, used to reset
 
8303
                                 * valstack_bottom on return; index is absolute.
 
8304
                                 * Note: idx_top not needed because top is set to 'nregs'
 
8305
                                 * always when returning to an Ecmascript activation.
 
8306
                                 */
 
8307
        int idx_retval;         /* Return value when returning to this activation
 
8308
                                 * (points to caller reg, not callee reg); index is absolute
 
8309
                                 * Note: only set if activation is -not topmost-.
 
8310
                                 */
 
8311
 
 
8312
        /* Current 'this' binding is the value just below idx_bottom.
 
8313
         * Previously, 'this' binding was handled with an index to the
 
8314
         * (calling) valstack.  This works for everything except tail
 
8315
         * calls, which must not "cumulate" valstack temps.
 
8316
         */
 
8317
 
 
8318
#if defined(DUK_USE_32BIT_PTRS) && !defined(DUK_USE_FUNC_NONSTD_CALLER_PROPERTY)
 
8319
        /* Minor optimization: pad structure to 2^N size on 32-bit platforms. */
 
8320
        int unused1;  /* pad to 2^N */
 
8321
#endif
 
8322
};
 
8323
 
 
8324
/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
 
8325
struct duk_catcher {
 
8326
        /* FIXME: typing */
 
8327
        duk_size_t callstack_index;     /* callstack index of related activation */
 
8328
        int flags;                      /* type and control flags */
 
8329
        int pc_base;                    /* resume execution from pc_base or pc_base+1 */
 
8330
        int idx_base;                   /* idx_base and idx_base+1 get completion value and type */
 
8331
        duk_hstring *h_varname;         /* borrowed reference to catch variable name (or NULL if none) */
 
8332
                                        /* (reference is valid as long activation exists) */
 
8333
};
 
8334
 
 
8335
struct duk_hthread {
 
8336
        /* shared object part */
 
8337
        duk_hobject obj;
 
8338
 
 
8339
        /* backpointers */
 
8340
        duk_heap *heap;
 
8341
 
 
8342
        /* current strictness flag: affects API calls */
 
8343
        duk_uint8_t strict;
 
8344
        duk_uint8_t state;
 
8345
        duk_uint8_t unused1;
 
8346
        duk_uint8_t unused2;
 
8347
 
 
8348
        /* sanity limits */
 
8349
        duk_size_t valstack_max;
 
8350
        duk_size_t callstack_max;
 
8351
        duk_size_t catchstack_max;
 
8352
 
 
8353
        /* XXX: valstack, callstack, and catchstack are currently assumed
 
8354
         * to have non-NULL pointers.  Relaxing this would not lead to big
 
8355
         * benefits (except perhaps for terminated threads).
 
8356
         */
 
8357
 
 
8358
        /* value stack: these are expressed as pointers for faster stack manipulation */
 
8359
        duk_tval *valstack;                     /* start of valstack allocation */
 
8360
        duk_tval *valstack_end;                 /* end of valstack allocation (exclusive) */
 
8361
        duk_tval *valstack_bottom;              /* bottom of current frame */
 
8362
        duk_tval *valstack_top;                 /* top of current frame (exclusive) */
 
8363
 
 
8364
        /* call stack */
 
8365
        duk_activation *callstack;
 
8366
        duk_size_t callstack_size;              /* allocation size */
 
8367
        duk_size_t callstack_top;               /* next to use, highest used is top - 1 */
 
8368
        duk_size_t callstack_preventcount;      /* number of activation records in callstack preventing a yield */
 
8369
 
 
8370
        /* catch stack */
 
8371
        duk_catcher *catchstack;
 
8372
        duk_size_t catchstack_size;             /* allocation size */
 
8373
        duk_size_t catchstack_top;              /* next to use, highest used is top - 1 */
 
8374
 
 
8375
        /* yield/resume book-keeping */
 
8376
        duk_hthread *resumer;                   /* who resumed us (if any) */
 
8377
 
 
8378
#ifdef DUK_USE_INTERRUPT_COUNTER
 
8379
        /* Interrupt counter for triggering a slow path check for execution
 
8380
         * timeout, debugger interaction such as breakpoints, etc.  This is
 
8381
         * actually a value copied from the heap structure into the current
 
8382
         * thread to be more convenient for the bytecode executor inner loop.
 
8383
         * The final value is copied back to the heap structure on a thread
 
8384
         * switch by DUK_HEAP_SWITCH_THREAD().
 
8385
         */
 
8386
        duk_int_t interrupt_counter;
 
8387
#endif
 
8388
 
 
8389
        /* Builtin-objects; may or may not be shared with other threads,
 
8390
         * threads existing in different "compartments" will have different
 
8391
         * built-ins.  Must be stored on a per-thread basis because there
 
8392
         * is no intermediate structure for a thread group / compartment.
 
8393
         * This takes quite a lot of space, currently 43x4 = 172 bytes on
 
8394
         * 32-bit platforms.
 
8395
         */
 
8396
        duk_hobject *builtins[DUK_NUM_BUILTINS];
 
8397
 
 
8398
        /* convenience copies from heap/vm for faster access */
 
8399
        duk_hstring **strs;                     /* (from duk_heap) */
 
8400
};
 
8401
 
 
8402
/*
 
8403
 *  Prototypes
 
8404
 */
 
8405
 
 
8406
void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
 
8407
void duk_hthread_create_builtin_objects(duk_hthread *thr);
 
8408
int duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
 
8409
void duk_hthread_terminate(duk_hthread *thr);
 
8410
 
 
8411
void duk_hthread_callstack_grow(duk_hthread *thr);
 
8412
void duk_hthread_callstack_shrink_check(duk_hthread *thr);
 
8413
void duk_hthread_callstack_unwind(duk_hthread *thr, int new_top);
 
8414
void duk_hthread_catchstack_grow(duk_hthread *thr);
 
8415
void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
 
8416
void duk_hthread_catchstack_unwind(duk_hthread *thr, int new_top);
 
8417
 
 
8418
duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
 
8419
void *duk_hthread_get_valstack_ptr(void *ud);  /* indirect allocs */
 
8420
void *duk_hthread_get_callstack_ptr(void *ud);  /* indirect allocs */
 
8421
void *duk_hthread_get_catchstack_ptr(void *ud);  /* indirect allocs */
 
8422
 
 
8423
#endif  /* DUK_HTHREAD_H_INCLUDED */
 
8424
#line 1 "duk_hbuffer.h"
 
8425
/*
 
8426
 *  Heap buffer representation.
 
8427
 *
 
8428
 *  Heap allocated user data buffer which is either:
 
8429
 *
 
8430
 *    1. A fixed size buffer (data follows header statically)
 
8431
 *    2. A dynamic size buffer (data pointer follows header)
 
8432
 *
 
8433
 *  The data pointer for a variable size buffer of zero size may be NULL.
 
8434
 */
 
8435
 
 
8436
#ifndef DUK_HBUFFER_H_INCLUDED
 
8437
#define DUK_HBUFFER_H_INCLUDED
 
8438
 
 
8439
/* Impose a maximum buffer length for now.  Restricted artificially to
 
8440
 * ensure resize computations or adding a heap header length won't
 
8441
 * overflow size_t.  The limit should be synchronized with
 
8442
 * DUK_HSTRING_MAX_BYTELEN.
 
8443
 */
 
8444
#define DUK_HBUFFER_MAX_BYTELEN                   (0x7fffffffUL)
 
8445
 
 
8446
#define DUK_HBUFFER_FLAG_DYNAMIC                  DUK_HEAPHDR_USER_FLAG(0)  /* buffer is resizable */
 
8447
 
 
8448
#define DUK_HBUFFER_HAS_DYNAMIC(x)                DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
 
8449
 
 
8450
#define DUK_HBUFFER_SET_DYNAMIC(x)                DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
 
8451
 
 
8452
#define DUK_HBUFFER_CLEAR_DYNAMIC(x)              DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
 
8453
 
 
8454
#define DUK_HBUFFER_FIXED_GET_DATA_PTR(x)         ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
 
8455
#define DUK_HBUFFER_FIXED_GET_SIZE(x)             ((x)->u.s.size)
 
8456
 
 
8457
#define DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(x)     ((x)->usable_size)
 
8458
#define DUK_HBUFFER_DYNAMIC_GET_USABLE_SIZE(x)    ((x)->usable_size)
 
8459
#define DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(x)     ((x)->usable_size - (x)->size)
 
8460
#define DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(x)  ((x)->curr_alloc)
 
8461
 
 
8462
/* gets the actual buffer contents which matches the current allocation size
 
8463
 * (may be NULL for zero size dynamic buffer)
 
8464
 */
 
8465
#define DUK_HBUFFER_GET_DATA_PTR(x)  ( \
 
8466
        DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
 
8467
                DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR((duk_hbuffer_dynamic *) (x)) : \
 
8468
                DUK_HBUFFER_FIXED_GET_DATA_PTR((duk_hbuffer_fixed *) (x)) \
 
8469
        )
 
8470
 
 
8471
/* gets the current user visible size, without accounting for a dynamic
 
8472
 * buffer's "spare" (= usable size).
 
8473
 */
 
8474
#define DUK_HBUFFER_GET_SIZE(x)         ((x)->size)
 
8475
 
 
8476
#define DUK_HBUFFER_SET_SIZE(x,val)  do { \
 
8477
                (x)->size = (val); \
 
8478
        } while (0)
 
8479
 
 
8480
/* growth parameters */
 
8481
#define DUK_HBUFFER_SPARE_ADD      16
 
8482
#define DUK_HBUFFER_SPARE_DIVISOR  16   /* 2^4 -> 1/16 = 6.25% spare */
 
8483
 
 
8484
struct duk_hbuffer {
 
8485
        duk_heaphdr hdr;
 
8486
 
 
8487
        /* it's not strictly necessary to track the current size, but
 
8488
         * it is useful for writing robust native code.
 
8489
         */
 
8490
 
 
8491
        size_t size;  /* current size (not counting a dynamic buffer's "spare") */
 
8492
 
 
8493
        /*
 
8494
         *  Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
 
8495
         *  flag.
 
8496
         *
 
8497
         *  If the flag is clear (the buffer is a fixed size one), the buffer
 
8498
         *  data follows the header directly, consisting of 'size' bytes.
 
8499
         *
 
8500
         *  If the flag is set, the actual buffer is allocated separately, and
 
8501
         *  a few control fields follow the header.  Specifically:
 
8502
         *
 
8503
         *    - a "void *" pointing to the current allocation
 
8504
         *    - a size_t indicating the full allocated size (always >= 'size')
 
8505
         *
 
8506
         *  Unlike strings, no terminator byte (NUL) is guaranteed after the
 
8507
         *  data.  This would be convenient, but would pad aligned user buffers
 
8508
         *  unnecessarily upwards in size.  For instance, if user code requested
 
8509
         *  a 64-byte dynamic buffer, 65 bytes would actually be allocated which
 
8510
         *  would then potentially round upwards to perhaps 68 or 72 bytes.
 
8511
         */
 
8512
};
 
8513
 
 
8514
#if defined(DUK_USE_ALIGN_8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
 
8515
#pragma pack(push, 8)
 
8516
#endif
 
8517
struct duk_hbuffer_fixed {
 
8518
        /* A union is used here as a portable struct size / alignment trick:
 
8519
         * by adding a 32-bit or a 64-bit (unused) union member, the size of
 
8520
         * the struct is effectively forced to be a multiple of 4 or 8 bytes
 
8521
         * (respectively) without increasing the size of the struct unless
 
8522
         * necessary.
 
8523
         */
 
8524
        union {
 
8525
                struct {
 
8526
                        duk_heaphdr hdr;
 
8527
                        size_t size;
 
8528
                } s;
 
8529
#if defined(DUK_USE_ALIGN_4)
 
8530
                duk_uint32_t dummy_for_align4;
 
8531
#elif defined(DUK_USE_ALIGN_8)
 
8532
                duk_uint64_t dummy_for_align8;
 
8533
#else
 
8534
                /* no extra padding */
 
8535
#endif
 
8536
        } u;
 
8537
 
 
8538
        /*
 
8539
         *  Data follows the struct header.  The struct size is padded by the
 
8540
         *  compiler based on the struct members.  This guarantees that the
 
8541
         *  buffer data will be aligned-by-4 but not necessarily aligned-by-8.
 
8542
         *
 
8543
         *  On platforms where alignment does not matter, the struct padding
 
8544
         *  could be removed (if there is any).  On platforms where alignment
 
8545
         *  by 8 is required, the struct size must be forced to be a multiple
 
8546
         *  of 8 by some means.  Without it, some user code may break, and also
 
8547
         *  Duktape itself breaks (e.g. the compiler stores duk_tvals in a
 
8548
         *  dynamic buffer).
 
8549
         */
 
8550
}
 
8551
#if defined(DUK_USE_ALIGN_8) && defined(DUK_USE_PACK_GCC_ATTR)
 
8552
__attribute__ ((aligned (8)))
 
8553
#elif defined(DUK_USE_ALIGN_8) && defined(DUK_USE_PACK_CLANG_ATTR)
 
8554
__attribute__ ((aligned (8)))
 
8555
#endif
 
8556
;
 
8557
#if defined(DUK_USE_ALIGN_8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
 
8558
#pragma pack(pop)
 
8559
#endif
 
8560
 
 
8561
struct duk_hbuffer_dynamic {
 
8562
        duk_heaphdr hdr;
 
8563
        size_t size;
 
8564
 
 
8565
        void *curr_alloc;  /* may be NULL if usable_size == 0 */
 
8566
        size_t usable_size;
 
8567
 
 
8568
        /*
 
8569
         *  Allocation size for 'curr_alloc' is usable_size directly.
 
8570
         *  There is no automatic NUL terminator for buffers (see above
 
8571
         *  for rationale).
 
8572
         *
 
8573
         *  'curr_alloc' is explicitly allocated with heap allocation
 
8574
         *  primitives and will thus always have alignment suitable for
 
8575
         *  e.g. duk_tval and an IEEE double.
 
8576
         */
 
8577
};
 
8578
 
 
8579
/*
 
8580
 *  Prototypes
 
8581
 */
 
8582
 
 
8583
duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, size_t size, int dynamic);
 
8584
void *duk_hbuffer_get_dynalloc_ptr(void *ud);  /* indirect allocs */
 
8585
 
 
8586
/* dynamic buffer ops */
 
8587
void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t new_size, size_t new_usable_size);
 
8588
void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
 
8589
void duk_hbuffer_compact(duk_hthread *thr, duk_hbuffer_dynamic *buf);
 
8590
void duk_hbuffer_append_bytes(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint8_t *data, size_t length);
 
8591
void duk_hbuffer_append_byte(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint8_t byte);
 
8592
size_t duk_hbuffer_append_cstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, const char *str);
 
8593
size_t duk_hbuffer_append_hstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_hstring *str);
 
8594
size_t duk_hbuffer_append_xutf8(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t codepoint);
 
8595
size_t duk_hbuffer_append_cesu8(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t codepoint);
 
8596
void duk_hbuffer_append_native_u32(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t val);
 
8597
void duk_hbuffer_insert_bytes(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint8_t *data, size_t length);
 
8598
void duk_hbuffer_insert_byte(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint8_t byte);
 
8599
size_t duk_hbuffer_insert_cstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, const char *str);
 
8600
size_t duk_hbuffer_insert_hstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_hstring *str);
 
8601
size_t duk_hbuffer_insert_xutf8(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint32_t codepoint);
 
8602
size_t duk_hbuffer_insert_cesu8(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint32_t codepoint);
 
8603
void duk_hbuffer_remove_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, size_t length);
 
8604
void duk_hbuffer_insert_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t dst_offset, size_t src_offset, size_t length);
 
8605
void duk_hbuffer_append_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t src_offset, size_t length);
 
8606
 
 
8607
#endif  /* DUK_HBUFFER_H_INCLUDED */
 
8608
 
 
8609
#line 1 "duk_heap.h"
 
8610
/*
 
8611
 *  Heap structure.
 
8612
 *
 
8613
 *  Heap contains allocated heap objects, interned strings, and built-in
 
8614
 *  strings for one or more threads.
 
8615
 */
 
8616
 
 
8617
#ifndef DUK_HEAP_H_INCLUDED
 
8618
#define DUK_HEAP_H_INCLUDED
 
8619
 
 
8620
/* alloc function typedefs in duktape.h */
 
8621
 
 
8622
/*
 
8623
 *  Heap flags
 
8624
 */
 
8625
 
 
8626
#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING                     (1 << 0)  /* mark-and-sweep is currently running */
 
8627
#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED            (1 << 1)  /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
 
8628
#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING                     (1 << 2)  /* refcount code is processing refzero list */
 
8629
#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING                       (1 << 3)  /* an error handler (user callback to augment/replace error) is running */
 
8630
 
 
8631
#define DUK__HEAP_HAS_FLAGS(heap,bits)               ((heap)->flags & (bits))
 
8632
#define DUK__HEAP_SET_FLAGS(heap,bits)  do { \
 
8633
                (heap)->flags |= (bits); \
 
8634
        } while (0)
 
8635
#define DUK__HEAP_CLEAR_FLAGS(heap,bits)  do { \
 
8636
                (heap)->flags &= ~(bits); \
 
8637
        } while (0)
 
8638
 
 
8639
#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)            DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
 
8640
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)   DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
 
8641
#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)            DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
 
8642
#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap)              DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
 
8643
 
 
8644
#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap)            DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
 
8645
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap)   DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
 
8646
#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap)            DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
 
8647
#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap)              DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
 
8648
 
 
8649
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap)          DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
 
8650
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
 
8651
#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap)          DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
 
8652
#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap)            DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
 
8653
 
 
8654
/*
 
8655
 *  Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
 
8656
 */
 
8657
 
 
8658
#define DUK_LJ_TYPE_UNKNOWN      0    /* unused */
 
8659
#define DUK_LJ_TYPE_RETURN       1    /* value1 -> return value */
 
8660
#define DUK_LJ_TYPE_THROW        2    /* value1 -> error object */
 
8661
#define DUK_LJ_TYPE_BREAK        3    /* value1 -> label number */
 
8662
#define DUK_LJ_TYPE_CONTINUE     4    /* value1 -> label number */
 
8663
#define DUK_LJ_TYPE_YIELD        5    /* value1 -> yield value, iserror -> error / normal */
 
8664
#define DUK_LJ_TYPE_RESUME       6    /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
 
8665
#define DUK_LJ_TYPE_NORMAL       7    /* pseudo-type to indicate a normal continuation (for 'finally' rethrowing) */
 
8666
 
 
8667
/* dummy non-zero value to be used as an argument for longjmp(), see man longjmp */
 
8668
#define DUK_LONGJMP_DUMMY_VALUE  1
 
8669
 
 
8670
/*
 
8671
 *  Mark-and-sweep flags
 
8672
 *
 
8673
 *  These are separate from heap level flags now but could be merged.
 
8674
 *  The heap structure only contains a 'base mark-and-sweep flags'
 
8675
 *  field and the GC caller can impose further flags.
 
8676
 */
 
8677
 
 
8678
#define DUK_MS_FLAG_EMERGENCY                (1 << 0)   /* emergency mode: try extra hard */
 
8679
#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE    (1 << 1)   /* don't resize stringtable (but may sweep it); needed during stringtable resize */
 
8680
#define DUK_MS_FLAG_NO_FINALIZERS            (1 << 2)   /* don't run finalizers (which may have arbitrary side effects) */
 
8681
#define DUK_MS_FLAG_NO_OBJECT_COMPACTION     (1 << 3)   /* don't compact objects; needed during object property allocation resize */
 
8682
 
 
8683
/*
 
8684
 *  Thread switching
 
8685
 *
 
8686
 *  To switch heap->curr_thread, use the macro below so that interrupt counters
 
8687
 *  get updated correctly.  The macro allows a NULL target thread because that
 
8688
 *  happens e.g. in call handling.
 
8689
 */
 
8690
 
 
8691
#ifdef DUK_USE_INTERRUPT_COUNTER
 
8692
#define DUK_HEAP_SWITCH_THREAD(heap,newthr)  duk_heap_switch_thread((heap), (newthr))
 
8693
#else
 
8694
#define DUK_HEAP_SWITCH_THREAD(heap,newthr)  do { \
 
8695
                (heap)->curr_thread = (newthr); \
 
8696
        } while (0)
 
8697
#endif
 
8698
 
 
8699
/*
 
8700
 *  Other heap related defines
 
8701
 */
 
8702
 
 
8703
/* Maximum duk_handle_call / duk_handle_safe_call depth.  Note that this
 
8704
 * does not limit bytecode executor internal call depth at all (e.g.
 
8705
 * for Ecmascript-to-Ecmascript calls, thread yields/resumes, etc).
 
8706
 * There is a separate callstack depth limit for threads.
 
8707
 */
 
8708
 
 
8709
#if defined(DUK_USE_DEEP_C_STACK)
 
8710
#define DUK_HEAP_DEFAULT_CALL_RECURSION_LIMIT             1000  /* assuming 0.5 kB between calls, about 500kB of stack */ 
 
8711
#else
 
8712
#define DUK_HEAP_DEFAULT_CALL_RECURSION_LIMIT             60    /* assuming 0.5 kB between calls, about 30kB of stack */ 
 
8713
#endif
 
8714
 
 
8715
/* Mark-and-sweep C recursion depth for marking phase; if reached,
 
8716
 * mark object as a TEMPROOT and use multi-pass marking.
 
8717
 */
 
8718
#if defined(DUK_USE_MARK_AND_SWEEP)
 
8719
#if defined(DUK_USE_GC_TORTURE)
 
8720
#define DUK_HEAP_MARK_AND_SWEEP_RECURSION_LIMIT   3
 
8721
#elif defined(DUK_USE_DEEP_C_STACK)
 
8722
#define DUK_HEAP_MARK_AND_SWEEP_RECURSION_LIMIT   256
 
8723
#else
 
8724
#define DUK_HEAP_MARK_AND_SWEEP_RECURSION_LIMIT   32
 
8725
#endif
 
8726
#endif
 
8727
 
 
8728
/* Mark-and-sweep interval is relative to combined count of objects and
 
8729
 * strings kept in the heap during the latest mark-and-sweep pass.
 
8730
 * Fixed point .8 multiplier and .0 adder.  Trigger count (interval) is
 
8731
 * decreased by each (re)allocation attempt (regardless of size), and each
 
8732
 * refzero processed object.
 
8733
 *
 
8734
 * 'SKIP' indicates how many (re)allocations to wait until a retry if
 
8735
 * GC is skipped because there is no thread do it with yet (happens
 
8736
 * only during init phases).
 
8737
 */
 
8738
#if defined(DUK_USE_MARK_AND_SWEEP)
 
8739
#if defined(DUK_USE_REFERENCE_COUNTING)
 
8740
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT              12800  /* 50x heap size */
 
8741
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD               1024
 
8742
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP              256
 
8743
#else
 
8744
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT              256    /* 1x heap size */
 
8745
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD               1024
 
8746
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP              256
 
8747
#endif
 
8748
#endif
 
8749
 
 
8750
/* Stringcache is used for speeding up char-offset-to-byte-offset
 
8751
 * translations for non-ASCII strings.
 
8752
 */
 
8753
#define DUK_HEAP_STRCACHE_SIZE                            4
 
8754
#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT                16  /* strings up to the this length are not cached */
 
8755
 
 
8756
/* helper to insert a (non-string) heap object into heap allocated list */
 
8757
#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr)     duk_heap_insert_into_heap_allocated((heap),(hdr))
 
8758
 
 
8759
/* Executor interrupt default interval when nothing else requires a
 
8760
 * smaller value.  The default interval must be small enough to allow
 
8761
 * for reasonable execution timeout checking.
 
8762
 */
 
8763
#ifdef DUK_USE_INTERRUPT_COUNTER
 
8764
#define DUK_HEAP_INTCTR_DEFAULT                           (256L * 1024L)
 
8765
#endif
 
8766
 
 
8767
/*
 
8768
 *  Stringtable
 
8769
 */
 
8770
 
 
8771
/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
 
8772
#define DUK_STRTAB_INITIAL_SIZE            17
 
8773
 
 
8774
/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
 
8775
#define DUK_STRTAB_DELETED_MARKER(heap)    ((duk_hstring *) heap)
 
8776
 
 
8777
/* resizing parameters */
 
8778
#define DUK_STRTAB_MIN_FREE_DIVISOR        4                /* load factor max 75% */
 
8779
#define DUK_STRTAB_MIN_USED_DIVISOR        4                /* load factor min 25% */
 
8780
#define DUK_STRTAB_GROW_ST_SIZE(n)         ((n) + (n))      /* used entries + approx 100% -> reset load to 50% */
 
8781
 
 
8782
#define DUK_STRTAB_U32_MAX_STRLEN          10               /* 4'294'967'295 */
 
8783
#define DUK_STRTAB_HIGHEST_32BIT_PRIME     0xfffffffbUL
 
8784
 
 
8785
/* probe sequence */
 
8786
#define DUK_STRTAB_HASH_INITIAL(hash,h_size)    ((hash) % (h_size))
 
8787
#define DUK_STRTAB_HASH_PROBE_STEP(hash)        DUK_UTIL_GET_HASH_PROBE_STEP((hash))
 
8788
 
 
8789
/*
 
8790
 *  Built-in strings
 
8791
 */
 
8792
 
 
8793
/* heap string indices are autogenerated in duk_strings.h */
 
8794
#define DUK_HEAP_GET_STRING(heap,idx)  ((heap)->strs[(idx)])
 
8795
 
 
8796
/*
 
8797
 *  Raw memory calls: relative to heap, but no GC interaction
 
8798
 */
 
8799
 
 
8800
#define DUK_ALLOC_RAW(heap,size) \
 
8801
        ((heap)->alloc_func((heap)->alloc_udata, (size)))
 
8802
 
 
8803
#define DUK_REALLOC_RAW(heap,ptr,newsize) \
 
8804
        ((heap)->realloc_func((heap)->alloc_udata, (ptr), (newsize)))
 
8805
 
 
8806
#define DUK_FREE_RAW(heap,ptr) \
 
8807
        ((heap)->free_func((heap)->alloc_udata, (ptr)))
 
8808
 
 
8809
/*
 
8810
 *  Memory calls: relative to heap, GC interaction, but no error throwing.
 
8811
 *
 
8812
 *  XXX: Currently a mark-and-sweep triggered by memory allocation will run
 
8813
 *  using the heap->heap_thread.  This thread is also used for running
 
8814
 *  mark-and-sweep finalization; this is not ideal because it breaks the
 
8815
 *  isolation between multiple global environments.
 
8816
 *
 
8817
 *  Notes:
 
8818
 *
 
8819
 *    - DUK_FREE() is required to ignore NULL and any other possible return
 
8820
 *      value of a zero-sized alloc/realloc (same as ANSI C free()).
 
8821
 * 
 
8822
 *    - There is no DUK_REALLOC_ZEROED (and checked variant) because we don't
 
8823
 *      assume to know the old size.  Caller must zero the reallocated memory.
 
8824
 *
 
8825
 *    - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
 
8826
 *      by an allocation failure might invalidate the original 'ptr', thus
 
8827
 *      causing a realloc retry to use an invalid pointer.  Example: we're
 
8828
 *      reallocating the value stack and a finalizer resizes the same value
 
8829
 *      stack during mark-and-sweep.  The indirect variant requests for the
 
8830
 *      current location of the pointer being reallocated using a callback
 
8831
 *      right before every realloc attempt; this circuitous approach is used
 
8832
 *      to avoid strict aliasing issues in a more straightforward indirect
 
8833
 *      pointer (void **) approach.  Note: the pointer in the storage
 
8834
 *      location is read but is NOT updated; the caller must do that.
 
8835
 */
 
8836
 
 
8837
/* callback for indirect reallocs, request for current pointer */
 
8838
typedef void *(*duk_mem_getptr)(void *ud);
 
8839
 
 
8840
#define DUK_ALLOC(heap,size)                            duk_heap_mem_alloc((heap), (size))
 
8841
#define DUK_ALLOC_ZEROED(heap,size)                     duk_heap_mem_alloc_zeroed((heap), (size))
 
8842
#define DUK_REALLOC(heap,ptr,newsize)                   duk_heap_mem_realloc((heap), (ptr), (newsize))
 
8843
#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize)        duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
 
8844
#define DUK_FREE(heap,ptr)                              duk_heap_mem_free((heap), (ptr))
 
8845
 
 
8846
/*
 
8847
 *  Memory calls: relative to a thread, GC interaction, throw error on alloc failure
 
8848
 */
 
8849
 
 
8850
/* XXX: add __func__; use DUK_FUNC_MACRO because __func__ is not always available */
 
8851
 
 
8852
#ifdef DUK_USE_VERBOSE_ERRORS
 
8853
#define DUK_ALLOC_CHECKED(thr,size)                     duk_heap_mem_alloc_checked((thr), (size), DUK_FILE_MACRO, DUK_LINE_MACRO)
 
8854
#define DUK_ALLOC_CHECKED_ZEROED(thr,size)              duk_heap_mem_alloc_checked_zeroed((thr), (size), DUK_FILE_MACRO, DUK_LINE_MACRO)
 
8855
#define DUK_REALLOC_CHECKED(thr,ptr,newsize)            duk_heap_mem_realloc_checked((thr), (ptr), (newsize), DUK_FILE_MACRO, DUK_LINE_MACRO)
 
8856
#define DUK_REALLOC_INDIRECT_CHECKED(thr,cb,ud,newsize) duk_heap_mem_realloc_indirect_checked((thr), (cb), (ud), (newsize), DUK_FILE_MACRO, DUK_LINE_MACRO)
 
8857
#define DUK_FREE_CHECKED(thr,ptr)                       duk_heap_mem_free((thr)->heap, (ptr))  /* must not fail */
 
8858
#else
 
8859
#define DUK_ALLOC_CHECKED(thr,size)                     duk_heap_mem_alloc_checked((thr), (size))
 
8860
#define DUK_ALLOC_CHECKED_ZEROED(thr,size)              duk_heap_mem_alloc_checked_zeroed((thr), (size))
 
8861
#define DUK_REALLOC_CHECKED(thr,ptr,newsize)            duk_heap_mem_realloc_checked((thr), (ptr), (newsize))
 
8862
#define DUK_REALLOC_INDIRECT_CHECKED(thr,cb,ud,newsize) duk_heap_mem_realloc_indirect_checked((thr), (cb), (ud), (newsize))
 
8863
#define DUK_FREE_CHECKED(thr,ptr)                       duk_heap_mem_free((thr)->heap, (ptr))  /* must not fail */
 
8864
#endif
 
8865
 
 
8866
/*
 
8867
 *  Memory constants
 
8868
 */
 
8869
 
 
8870
#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT           5   /* Retry allocation after mark-and-sweep for this
 
8871
                                                              * many times.  A single mark-and-sweep round is
 
8872
                                                              * not guaranteed to free all unreferenced memory
 
8873
                                                              * because of finalization (in fact, ANY number of
 
8874
                                                              * rounds is strictly not enough).
 
8875
                                                              */
 
8876
 
 
8877
#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT  3  /* Starting from this round, use emergency mode
 
8878
                                                              * for mark-and-sweep.
 
8879
                                                              */
 
8880
 
 
8881
/*
 
8882
 *  String cache should ideally be at duk_hthread level, but that would
 
8883
 *  cause string finalization to slow down relative to the number of
 
8884
 *  threads; string finalization must check the string cache for "weak"
 
8885
 *  references to the string being finalized to avoid dead pointers.
 
8886
 *
 
8887
 *  Thus, string caches are now at the heap level now.
 
8888
 */
 
8889
 
 
8890
struct duk_strcache {
 
8891
        duk_hstring *h;
 
8892
        duk_uint32_t bidx;
 
8893
        duk_uint32_t cidx;
 
8894
};
 
8895
 
 
8896
/*
 
8897
 *  Longjmp state, contains the information needed to perform a longjmp.
 
8898
 *  Longjmp related values are written to value1, value2, and iserror.
 
8899
 */
 
8900
 
 
8901
struct duk_ljstate {
 
8902
        duk_jmpbuf *jmpbuf_ptr;   /* current setjmp() catchpoint */
 
8903
        int type;                 /* longjmp type */
 
8904
        duk_tval value1;          /* 1st related value (type specific) */
 
8905
        duk_tval value2;          /* 2nd related value (type specific) */
 
8906
        int iserror;              /* isError flag for yield */
 
8907
};
 
8908
 
 
8909
/*
 
8910
 *  Main heap structure
 
8911
 */
 
8912
 
 
8913
struct duk_heap {
 
8914
        int flags;
 
8915
 
 
8916
        /* allocator functions */
 
8917
        duk_alloc_function alloc_func;
 
8918
        duk_realloc_function realloc_func;
 
8919
        duk_free_function free_func;
 
8920
        void *alloc_udata;
 
8921
 
 
8922
        /* Fatal error handling, called e.g. when a longjmp() is needed but
 
8923
         * lj.jmpbuf_ptr is NULL.  fatal_func must never return; it's not
 
8924
         * declared as "noreturn" because doing that for typedefs is a bit
 
8925
         * challenging portability-wise.
 
8926
         */
 
8927
        duk_fatal_function fatal_func;
 
8928
 
 
8929
        /* allocated heap objects */
 
8930
        duk_heaphdr *heap_allocated;
 
8931
 
 
8932
        /* work list for objects whose refcounts are zero but which have not been
 
8933
         * "finalized"; avoids recursive C calls when refcounts go to zero in a
 
8934
         * chain of objects.
 
8935
         */
 
8936
#ifdef DUK_USE_REFERENCE_COUNTING
 
8937
        duk_heaphdr *refzero_list;
 
8938
        duk_heaphdr *refzero_list_tail;
 
8939
#endif
 
8940
 
 
8941
#ifdef DUK_USE_MARK_AND_SWEEP
 
8942
        /* mark-and-sweep control */
 
8943
#ifdef DUK_USE_VOLUNTARY_GC
 
8944
        int mark_and_sweep_trigger_counter;
 
8945
#endif
 
8946
        int mark_and_sweep_recursion_depth;
 
8947
 
 
8948
        /* mark-and-sweep flags automatically active (used for critical sections) */
 
8949
        int mark_and_sweep_base_flags;
 
8950
 
 
8951
        /* work list for objects to be finalized (by mark-and-sweep) */
 
8952
        duk_heaphdr *finalize_list;
 
8953
#endif
 
8954
 
 
8955
        /* longjmp state */
 
8956
        duk_ljstate lj;
 
8957
 
 
8958
        /* marker for detecting internal "double faults", see duk_error_throw.c */
 
8959
        int handling_error;
 
8960
 
 
8961
        /* heap thread, used internally and for finalization */
 
8962
        duk_hthread *heap_thread;
 
8963
 
 
8964
        /* current thread */
 
8965
        duk_hthread *curr_thread;       /* currently running thread */
 
8966
 
 
8967
        /* heap level "stash" object (e.g., various reachability roots) */
 
8968
        duk_hobject *heap_object;
 
8969
 
 
8970
        /* heap level temporary log formatting buffer */
 
8971
        duk_hbuffer_dynamic *log_buffer;
 
8972
 
 
8973
        /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
 
8974
        int call_recursion_depth;
 
8975
        int call_recursion_limit;
 
8976
 
 
8977
        /* mix-in value for computing string hashes; should be reasonably unpredictable */
 
8978
        duk_uint32_t hash_seed;
 
8979
 
 
8980
        /* rnd_state for duk_util_tinyrandom.c */
 
8981
        duk_uint32_t rnd_state;
 
8982
 
 
8983
        /* interrupt counter */
 
8984
#ifdef DUK_USE_INTERRUPT_COUNTER
 
8985
        duk_int_t interrupt_init;     /* start value for current countdown */
 
8986
        duk_int_t interrupt_counter;  /* countdown state (mirrored in current thread state) */
 
8987
#endif
 
8988
 
 
8989
        /* string intern table (weak refs) */
 
8990
        duk_hstring **st;
 
8991
        duk_uint32_t st_size;     /* alloc size in elements */
 
8992
        duk_uint32_t st_used;     /* used elements (includes DELETED) */
 
8993
 
 
8994
        /* string access cache (codepoint offset -> byte offset) for fast string
 
8995
         * character looping; 'weak' reference which needs special handling in GC.
 
8996
         */
 
8997
        duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
 
8998
 
 
8999
        /* built-in strings */
 
9000
        duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
 
9001
};
 
9002
 
 
9003
/*
 
9004
 *  Prototypes
 
9005
 */
 
9006
 
 
9007
duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
 
9008
                         duk_realloc_function realloc_func,
 
9009
                         duk_free_function free_func,
 
9010
                         void *alloc_udata,
 
9011
                         duk_fatal_function fatal_func);
 
9012
void duk_heap_free(duk_heap *heap);
 
9013
void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
 
9014
 
 
9015
void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
 
9016
#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
 
9017
void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
 
9018
#endif
 
9019
#ifdef DUK_USE_INTERRUPT_COUNTER
 
9020
void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
 
9021
#endif
 
9022
 
 
9023
duk_hstring *duk_heap_string_lookup(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen);
 
9024
duk_hstring *duk_heap_string_intern(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen);
 
9025
duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, duk_uint8_t *str, duk_uint32_t len);
 
9026
duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
 
9027
duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
 
9028
duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
 
9029
void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
 
9030
#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
 
9031
void duk_heap_force_stringtable_resize(duk_heap *heap);
 
9032
#endif
 
9033
 
 
9034
void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
 
9035
duk_uint32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint32_t char_offset);
 
9036
 
 
9037
#ifdef DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
 
9038
void *duk_default_alloc_function(void *udata, size_t size);
 
9039
void *duk_default_realloc_function(void *udata, void *ptr, size_t newsize);
 
9040
void duk_default_free_function(void *udata, void *ptr);
 
9041
#endif
 
9042
 
 
9043
void *duk_heap_mem_alloc(duk_heap *heap, size_t size);
 
9044
void *duk_heap_mem_alloc_zeroed(duk_heap *heap, size_t size);
 
9045
void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, size_t newsize);
 
9046
void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, size_t newsize);
 
9047
void duk_heap_mem_free(duk_heap *heap, void *ptr);
 
9048
 
 
9049
#ifdef DUK_USE_VERBOSE_ERRORS
 
9050
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size, const char *filename, int line);
 
9051
void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, size_t size, const char *filename, int line);
 
9052
void *duk_heap_mem_realloc_checked(duk_hthread *thr, void *ptr, size_t newsize, const char *filename, int line);
 
9053
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize, const char *filename, int line);
 
9054
#else
 
9055
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size);
 
9056
void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, size_t size);
 
9057
void *duk_heap_mem_realloc_checked(duk_hthread *thr, void *ptr, size_t newsize);
 
9058
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize);
 
9059
#endif
 
9060
 
 
9061
#ifdef DUK_USE_REFERENCE_COUNTING
 
9062
void duk_heap_tval_incref(duk_tval *tv);
 
9063
void duk_heap_tval_decref(duk_hthread *thr, duk_tval *tv);
 
9064
void duk_heap_heaphdr_incref(duk_heaphdr *h);
 
9065
void duk_heap_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
 
9066
void duk_heap_refcount_finalize_heaphdr(duk_hthread *thr, duk_heaphdr *hdr);
 
9067
#else
 
9068
/* no refcounting */
 
9069
#endif
 
9070
 
 
9071
#ifdef DUK_USE_MARK_AND_SWEEP
 
9072
int duk_heap_mark_and_sweep(duk_heap *heap, int flags);
 
9073
#endif
 
9074
 
 
9075
duk_uint32_t duk_heap_hashstring(duk_heap *heap, duk_uint8_t *str, duk_size_t len);
 
9076
 
 
9077
#endif  /* DUK_HEAP_H_INCLUDED */
 
9078
 
 
9079
#line 1 "duk_debug.h"
 
9080
/*
 
9081
 *  Debugging macros, DUK_DPRINT() and its variants in particular.
 
9082
 *
 
9083
 *  DUK_DPRINT() allows formatted debug prints, and supports standard
 
9084
 *  and Duktape specific formatters.  See duk_debug_vsnprintf.c for details.
 
9085
 */
 
9086
 
 
9087
#ifndef DUK_DEBUG_H_INCLUDED
 
9088
#define DUK_DEBUG_H_INCLUDED
 
9089
 
 
9090
#ifdef DUK_USE_DEBUG
 
9091
 
 
9092
/*
 
9093
 *  Exposed debug macros: debugging enabled
 
9094
 */
 
9095
 
 
9096
#define DUK_LEVEL_DEBUG    1
 
9097
#define DUK_LEVEL_DDEBUG   2
 
9098
#define DUK_LEVEL_DDDEBUG  3
 
9099
 
 
9100
#ifdef DUK_USE_VARIADIC_MACROS
 
9101
 
 
9102
/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
 
9103
 * possible compile time, but waste some space with shared function names.
 
9104
 */
 
9105
#define DUK__DEBUG_LOG(lev,...)  duk_debug_log((lev), DUK_FILE_MACRO, (int) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
 
9106
 
 
9107
#define DUK_DPRINT(...)          DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
 
9108
 
 
9109
#ifdef DUK_USE_DDEBUG
 
9110
#define DUK_DDPRINT(...)         DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
 
9111
#else
 
9112
#define DUK_DDPRINT(...)
 
9113
#endif
 
9114
 
 
9115
#ifdef DUK_USE_DDDEBUG
 
9116
#define DUK_DDDPRINT(...)        DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
 
9117
#else
 
9118
#define DUK_DDDPRINT(...)
 
9119
#endif
 
9120
 
 
9121
#else  /* DUK_USE_VARIADIC_MACROS */
 
9122
 
 
9123
#define DUK__DEBUG_STASH(lev)    \
 
9124
        (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", DUK_FILE_MACRO), \
 
9125
        duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
 
9126
        (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%d", (int) DUK_LINE_MACRO), \
 
9127
        duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
 
9128
        (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", DUK_FUNC_MACRO), \
 
9129
        duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
 
9130
        (void) (duk_debug_level_stash = (lev))
 
9131
 
 
9132
/* Without variadic macros resort to comma expression trickery to handle debug
 
9133
 * prints.  This generates a lot of harmless warnings, unfortunately.
 
9134
 */
 
9135
 
 
9136
#ifdef DUK_USE_DEBUG
 
9137
#define DUK_DPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log  /* args go here in parens */
 
9138
#else
 
9139
#define DUK_DPRINT  0 && /* args go here as a comma expression in parens */
 
9140
#endif
 
9141
 
 
9142
#ifdef DUK_USE_DDEBUG
 
9143
#define DUK_DDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log  /* args go here in parens */
 
9144
#else
 
9145
#define DUK_DDPRINT  0 && 
 
9146
#endif
 
9147
 
 
9148
#ifdef DUK_USE_DDDEBUG
 
9149
#define DUK_DDDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log  /* args go here in parens */
 
9150
#else
 
9151
#define DUK_DDDPRINT  0 && 
 
9152
#endif
 
9153
 
 
9154
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9155
 
 
9156
/* object dumpers */
 
9157
 
 
9158
#define DUK_DEBUG_DUMP_HEAP(x)               duk_debug_dump_heap((x))
 
9159
#define DUK_DEBUG_DUMP_HSTRING(x)            /* XXX: unimplemented */
 
9160
#define DUK_DEBUG_DUMP_HOBJECT(x)            duk_debug_dump_hobject((x))
 
9161
#define DUK_DEBUG_DUMP_HCOMPILEDFUNCTION(x)  /* XXX: unimplemented */
 
9162
#define DUK_DEBUG_DUMP_HNATIVEFUNCTION(x)    /* XXX: unimplemented */
 
9163
#define DUK_DEBUG_DUMP_HTHREAD(thr)          duk_debug_dump_hobject((duk_hobject *) (thr))
 
9164
#define DUK_DEBUG_DUMP_CALLSTACK(thr)        duk_debug_dump_callstack((thr))
 
9165
#define DUK_DEBUG_DUMP_ACTIVATION(thr,act)   duk_debug_dump_activation((thr),(act))
 
9166
 
 
9167
/* summary macros */
 
9168
 
 
9169
#define DUK_DEBUG_SUMMARY_INIT()  do { \
 
9170
                DUK_MEMZERO(duk_debug_summary_buf, sizeof(duk_debug_summary_buf)); \
 
9171
                duk_debug_summary_idx = 0; \
 
9172
        } while (0)
 
9173
 
 
9174
#define DUK_DEBUG_SUMMARY_CHAR(ch)  do { \
 
9175
                duk_debug_summary_buf[duk_debug_summary_idx++] = (ch); \
 
9176
                if ((duk_size_t) duk_debug_summary_idx >= (duk_size_t) (sizeof(duk_debug_summary_buf) - 1)) { \
 
9177
                        duk_debug_summary_buf[duk_debug_summary_idx++] = (char) 0; \
 
9178
                        DUK_DPRINT("    %s", duk_debug_summary_buf); \
 
9179
                        DUK_DEBUG_SUMMARY_INIT(); \
 
9180
                } \
 
9181
        } while (0)
 
9182
 
 
9183
#define DUK_DEBUG_SUMMARY_FINISH()  do { \
 
9184
                if (duk_debug_summary_idx > 0) { \
 
9185
                        duk_debug_summary_buf[duk_debug_summary_idx++] = (char) 0; \
 
9186
                        DUK_DPRINT("    %s", duk_debug_summary_buf); \
 
9187
                        DUK_DEBUG_SUMMARY_INIT(); \
 
9188
                } \
 
9189
        } while (0)
 
9190
 
 
9191
#else  /* DUK_USE_DEBUG */
 
9192
 
 
9193
/*
 
9194
 *  Exposed debug macros: debugging disabled
 
9195
 */
 
9196
 
 
9197
#ifdef DUK_USE_VARIADIC_MACROS
 
9198
 
 
9199
#define DUK_DPRINT(...)
 
9200
#define DUK_DDPRINT(...)
 
9201
#define DUK_DDDPRINT(...)
 
9202
 
 
9203
#else  /* DUK_USE_VARIADIC_MACROS */
 
9204
 
 
9205
#define DUK_DPRINT    0 && /* args go here as a comma expression in parens */
 
9206
#define DUK_DDPRINT   0 && 
 
9207
#define DUK_DDDPRINT  0 && 
 
9208
 
 
9209
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9210
 
 
9211
#define DUK_DEBUG_DUMP_HEAP(x)
 
9212
#define DUK_DEBUG_DUMP_HSTRING(x)
 
9213
#define DUK_DEBUG_DUMP_HOBJECT(x)
 
9214
#define DUK_DEBUG_DUMP_HCOMPILEDFUNCTION(x)
 
9215
#define DUK_DEBUG_DUMP_HNATIVEFUNCTION(x)
 
9216
#define DUK_DEBUG_DUMP_HTHREAD(x)
 
9217
 
 
9218
#define DUK_DEBUG_SUMMARY_INIT()
 
9219
#define DUK_DEBUG_SUMMARY_CHAR(ch)
 
9220
#define DUK_DEBUG_SUMMARY_FINISH()
 
9221
 
 
9222
#endif  /* DUK_DEBUG */
 
9223
 
 
9224
/*
 
9225
 *  Structs
 
9226
 */
 
9227
 
 
9228
#ifdef DUK_USE_DEBUG
 
9229
struct duk_fixedbuffer {
 
9230
        duk_uint8_t *buffer;
 
9231
        duk_uint32_t length;
 
9232
        duk_uint32_t offset;
 
9233
        int truncated;
 
9234
};
 
9235
#endif
 
9236
 
 
9237
/*
 
9238
 *  Prototypes
 
9239
 */
 
9240
 
 
9241
#ifdef DUK_USE_DEBUG
 
9242
int duk_debug_vsnprintf(char *str, size_t size, const char *format, va_list ap);
 
9243
int duk_debug_snprintf(char *str, size_t size, const char *format, ...);
 
9244
void duk_debug_format_funcptr(char *buf, int buf_size, unsigned char *fptr, int fptr_size);
 
9245
 
 
9246
#ifdef DUK_USE_VARIADIC_MACROS
 
9247
void duk_debug_log(int level, const char *file, int line, const char *func, char *fmt, ...);
 
9248
#else
 
9249
/* parameter passing, not thread safe */
 
9250
#define DUK_DEBUG_STASH_SIZE  128
 
9251
extern char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
 
9252
extern char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
 
9253
extern char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
 
9254
extern int duk_debug_level_stash;
 
9255
extern void duk_debug_log(char *fmt, ...);
 
9256
#endif
 
9257
 
 
9258
void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_uint32_t length);
 
9259
void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
 
9260
void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
 
9261
void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
 
9262
int duk_fb_is_full(duk_fixedbuffer *fb);
 
9263
 
 
9264
void duk_debug_dump_heap(duk_heap *heap);
 
9265
void duk_debug_heap_graphviz(duk_heap *heap);
 
9266
void duk_debug_dump_hobject(duk_hobject *obj);
 
9267
void duk_debug_dump_hthread(duk_hthread *thr);
 
9268
void duk_debug_dump_callstack(duk_hthread *thr);
 
9269
void duk_debug_dump_activation(duk_hthread *thr, duk_activation *act);
 
9270
 
 
9271
#define DUK_DEBUG_SUMMARY_BUF_SIZE  76
 
9272
extern char duk_debug_summary_buf[DUK_DEBUG_SUMMARY_BUF_SIZE];
 
9273
extern int duk_debug_summary_idx;
 
9274
 
 
9275
#endif  /* DUK_USE_DEBUG */
 
9276
 
 
9277
#endif  /* DUK_DEBUG_H_INCLUDED */
 
9278
 
 
9279
#line 1 "duk_error.h"
 
9280
/*
 
9281
 *  Error handling macros, assertion macro, error codes.
 
9282
 *
 
9283
 *  There are three level of 'errors':
 
9284
 *
 
9285
 *    1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
 
9286
 *    2. Fatal errors, relative to a heap, cause fatal handler to be called.
 
9287
 *    3. Panic errors, unrelated to a heap and cause a process exit.
 
9288
 *
 
9289
 *  Panics are used by the default fatal error handler and by debug code
 
9290
 *  such as assertions.  By providing a proper fatal error handler, user
 
9291
 *  code can avoid panics in non-debug builds.
 
9292
 */
 
9293
 
 
9294
#ifndef DUK_ERROR_H_INCLUDED
 
9295
#define DUK_ERROR_H_INCLUDED
 
9296
 
 
9297
/*
 
9298
 *  Error codes: defined in duktape.h
 
9299
 *
 
9300
 *  Error codes are used as a shorthand to throw exceptions from inside
 
9301
 *  the implementation.  The appropriate Ecmascript object is constructed
 
9302
 *  based on the code.  Ecmascript code throws objects directly.  The error
 
9303
 *  codes are defined in the public API header because they are also used
 
9304
 *  by calling code.
 
9305
 */
 
9306
 
 
9307
/*
 
9308
 *  Normal error
 
9309
 *
 
9310
 *  Normal error is thrown with a longjmp() through the current setjmp()
 
9311
 *  catchpoint record in the duk_heap.  The 'curr_thread' of the duk_heap
 
9312
 *  identifies the throwing thread.
 
9313
 * 
 
9314
 *  Error formatting is not always necessary but there are no separate calls
 
9315
 *  (to minimize code size).  Error object creation will consume a considerable
 
9316
 *  amount of time, compared to which formatting is probably trivial.  Note
 
9317
 *  that special formatting (provided by DUK_DEBUG macros) is NOT available.
 
9318
 *
 
9319
 *  The _RAW variants allow the caller to specify file and line.  This makes
 
9320
 *  it easier to write checked calls which want to use the call site of the
 
9321
 *  checked function, not the error macro call inside the checked function.
 
9322
 *
 
9323
 *  We prefer the standard variadic macros; if they are not available, we
 
9324
 *  fall back to awkward hacks.
 
9325
 */
 
9326
 
 
9327
#ifdef DUK_USE_VERBOSE_ERRORS
 
9328
 
 
9329
#ifdef DUK_USE_VARIADIC_MACROS
 
9330
 
 
9331
/* __VA_ARGS__ has comma issues for empty lists, so we mandate at least 1 argument for '...' (format string) */
 
9332
#define DUK_ERROR(thr,err,...)                    duk_err_handle_error(DUK_FILE_MACRO, (int) DUK_LINE_MACRO, (thr), (err), __VA_ARGS__)
 
9333
#define DUK_ERROR_RAW(file,line,thr,err,...)      duk_err_handle_error((file), (line), (thr), (err), __VA_ARGS__)
 
9334
 
 
9335
#else  /* DUK_USE_VARIADIC_MACROS */
 
9336
 
 
9337
/* Parameter passing here is not thread safe.  We rely on the __FILE__
 
9338
 * pointer being a constant which can be passed through a global.
 
9339
 */
 
9340
 
 
9341
#define DUK_ERROR  \
 
9342
        duk_err_file_stash = (const char *) DUK_FILE_MACRO, \
 
9343
        duk_err_line_stash = (int) DUK_LINE_MACRO, \
 
9344
        (void) duk_err_handle_error_stash  /* arguments follow */
 
9345
#define DUK_ERROR_RAW                             duk_err_handle_error
 
9346
 
 
9347
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9348
 
 
9349
#else  /* DUK_USE_VERBOSE_ERRORS */
 
9350
 
 
9351
#ifdef DUK_USE_VARIADIC_MACROS
 
9352
 
 
9353
#define DUK_ERROR(thr,err,...)                    duk_err_handle_error((thr), (err))
 
9354
#define DUK_ERROR_RAW(file,line,thr,err,...)      duk_err_handle_error((thr), (err))
 
9355
 
 
9356
#else  /* DUK_USE_VARIADIC_MACROS */
 
9357
 
 
9358
/* This is sub-optimal because arguments will be passed but ignored, and the strings
 
9359
 * will go into the object file.  Can't think of how to do this portably and still
 
9360
 * relatively conveniently.
 
9361
 */
 
9362
#define DUK_ERROR                                 duk_err_handle_error_nonverbose1
 
9363
#define DUK_ERROR_RAW                             duk_err_handle_error_nonverbose2
 
9364
 
 
9365
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9366
 
 
9367
#endif  /* DUK_USE_VERBOSE_ERRORS */
 
9368
 
 
9369
/*
 
9370
 *  Fatal error
 
9371
 *
 
9372
 *  There are no fatal error macros at the moment.  There are so few call
 
9373
 *  sites that the fatal error handler is called directly.
 
9374
 */
 
9375
 
 
9376
/*
 
9377
 *  Panic error
 
9378
 *
 
9379
 *  Panic errors are not relative to either a heap or a thread, and cause
 
9380
 *  DUK_PANIC() macro to be invoked.  Unlesa a user provides DUK_OPT_PANIC_HANDLER,
 
9381
 *  DUK_PANIC() calls a helper which prints out the error and causes a process
 
9382
 *  exit.
 
9383
 *
 
9384
 *  The user can override the macro to provide custom handling.  A macro is
 
9385
 *  used to allow the user to have inline panic handling if desired (without
 
9386
 *  causing a potentially risky function call).
 
9387
 *
 
9388
 *  Panics are only used in debug code such as assertions, and by the default
 
9389
 *  fatal error handler.
 
9390
 */
 
9391
 
 
9392
#if defined(DUK_USE_PANIC_HANDLER)
 
9393
/* already defined, good */
 
9394
#define DUK_PANIC(code,msg)  DUK_USE_PANIC_HANDLER((code),(msg))
 
9395
#else
 
9396
#define DUK_PANIC(code,msg)  duk_default_panic_handler((code),(msg))
 
9397
#endif  /* DUK_USE_PANIC_HANDLER */
 
9398
 
 
9399
/*
 
9400
 *  Assert macro: failure causes panic.
 
9401
 */
 
9402
 
 
9403
#ifdef DUK_USE_ASSERTIONS
 
9404
 
 
9405
/* the message should be a compile time constant without formatting (less risk);
 
9406
 * we don't care about assertion text size because they're not used in production
 
9407
 * builds.
 
9408
 */
 
9409
#define DUK_ASSERT(x)  do { \
 
9410
        if (!(x)) { \
 
9411
                DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
 
9412
                        "assertion failed: " #x \
 
9413
                        " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
 
9414
        } \
 
9415
        } while (0)
 
9416
 
 
9417
#else  /* DUK_USE_ASSERTIONS */
 
9418
 
 
9419
#define DUK_ASSERT(x)  do { /* assertion omitted */ } while(0)
 
9420
 
 
9421
#endif  /* DUK_USE_ASSERTIONS */
 
9422
 
 
9423
/* this variant is used when an assert would generate a compile warning by
 
9424
 * being always true (e.g. >= 0 comparison for an unsigned value
 
9425
 */
 
9426
#define DUK_ASSERT_DISABLE(x)  do { /* assertion disabled */ } while(0)
 
9427
 
 
9428
/*
 
9429
 *  Assertion helpers
 
9430
 */
 
9431
 
 
9432
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
 
9433
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)  do { \
 
9434
                DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
 
9435
        } while (0)
 
9436
#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv)  do { \
 
9437
                if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
 
9438
                        DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
 
9439
                } \
 
9440
        } while (0)
 
9441
#else
 
9442
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)  /* no refcount check */
 
9443
#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv)    /* no refcount check */
 
9444
#endif
 
9445
 
 
9446
/* FIXME: fix typing to match duk_get_top() eventual return value type */
 
9447
#define DUK_ASSERT_TOP(ctx,n)  DUK_ASSERT((duk_int_t) duk_get_top((ctx)) == (duk_int_t) (n))
 
9448
 
 
9449
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
 
9450
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval)  do { \
 
9451
                duk_double_union assert_tmp_du; \
 
9452
                assert_tmp_du.d = (dval); \
 
9453
                DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&assert_tmp_du)); \
 
9454
        } while (0)
 
9455
#else
 
9456
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval)  /* nop */
 
9457
#endif
 
9458
 
 
9459
/*
 
9460
 *  Helper for valstack space
 
9461
 *
 
9462
 *  Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
 
9463
 *  required for its own use, and any child calls which are not (a) Duktape API calls
 
9464
 *  or (b) Duktape calls which involve extending the valstack (e.g. getter call).
 
9465
 */
 
9466
 
 
9467
#define DUK_VALSTACK_ASSERT_EXTRA  5  /* this is added to checks to allow for Duktape
 
9468
                                        * API calls in addition to function's own use
 
9469
                                        */
 
9470
#if defined(DUK_USE_ASSERTIONS)
 
9471
#define DUK_ASSERT_VALSTACK_SPACE(thr,n)   do { \
 
9472
                DUK_ASSERT((thr) != NULL); \
 
9473
                DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
 
9474
        } while (0)
 
9475
#else
 
9476
#define DUK_ASSERT_VALSTACK_SPACE(thr,n)   /* no valstack space check */
 
9477
#endif
 
9478
 
 
9479
/*
 
9480
 *  Prototypes
 
9481
 */
 
9482
 
 
9483
#ifdef DUK_USE_VERBOSE_ERRORS
 
9484
#ifdef DUK_USE_VARIADIC_MACROS
 
9485
DUK_NORETURN(void duk_err_handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...));
 
9486
#else  /* DUK_USE_VARIADIC_MACROS */
 
9487
extern const char *duk_err_file_stash;
 
9488
extern int duk_err_line_stash;
 
9489
DUK_NORETURN(void duk_err_handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...));
 
9490
DUK_NORETURN(void duk_err_handle_error_stash(duk_hthread *thr, int code, const char *fmt, ...));
 
9491
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9492
#else  /* DUK_USE_VERBOSE_ERRORS */
 
9493
#ifdef DUK_USE_VARIADIC_MACROS
 
9494
DUK_NORETURN(void duk_err_handle_error(duk_hthread *thr, int code));
 
9495
#else  /* DUK_USE_VARIADIC_MACROS */
 
9496
DUK_NORETURN(void duk_err_handle_error_nonverbose1(duk_hthread *thr, int code, const char *fmt, ...));
 
9497
DUK_NORETURN(void duk_err_handle_error_nonverbose2(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...));
 
9498
#endif  /* DUK_USE_VARIADIC_MACROS */
 
9499
#endif  /* DUK_USE_VERBOSE_ERRORS */
 
9500
 
 
9501
#ifdef DUK_USE_VERBOSE_ERRORS
 
9502
DUK_NORETURN(void duk_err_create_and_throw(duk_hthread *thr, duk_uint32_t code, const char *msg, const char *filename, int line));
 
9503
#else
 
9504
DUK_NORETURN(void duk_err_create_and_throw(duk_hthread *thr, duk_uint32_t code));
 
9505
#endif
 
9506
 
 
9507
DUK_NORETURN(void duk_error_throw_from_negative_rc(duk_hthread *thr, int rc));
 
9508
 
 
9509
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
 
9510
void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, int line, int noblame_fileline);
 
9511
#endif
 
9512
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
9513
void duk_err_augment_error_throw(duk_hthread *thr);
 
9514
#endif
 
9515
 
 
9516
DUK_NORETURN(void duk_err_longjmp(duk_hthread *thr));
 
9517
 
 
9518
DUK_NORETURN(void duk_default_fatal_handler(duk_context *ctx, int code, const char *msg));
 
9519
 
 
9520
#if !defined(DUK_USE_PANIC_HANDLER)
 
9521
DUK_NORETURN(void duk_default_panic_handler(int code, const char *msg));
 
9522
#endif
 
9523
 
 
9524
void duk_err_setup_heap_ljstate(duk_hthread *thr, int lj_type);
 
9525
 
 
9526
duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, int err_code);
 
9527
 
 
9528
#endif  /* DUK_ERROR_H_INCLUDED */
 
9529
 
 
9530
#line 1 "duk_util.h"
 
9531
/*
 
9532
 *  Utilities
 
9533
 */
 
9534
 
 
9535
#ifndef DUK_UTIL_H_INCLUDED
 
9536
#define DUK_UTIL_H_INCLUDED
 
9537
 
 
9538
#define DUK_UTIL_MIN_HASH_PRIME  17  /* must match genhashsizes.py */
 
9539
 
 
9540
#define DUK_UTIL_GET_HASH_PROBE_STEP(hash)  (duk_util_probe_steps[(hash) & 0x1f])
 
9541
 
 
9542
/*
 
9543
 *  Bitstream decoder
 
9544
 */
 
9545
 
 
9546
struct duk_bitdecoder_ctx {
 
9547
        const duk_uint8_t *data;
 
9548
        duk_size_t offset;
 
9549
        duk_size_t length;
 
9550
        duk_uint32_t currval;
 
9551
        duk_small_int_t currbits;
 
9552
};
 
9553
 
 
9554
/*
 
9555
 *  Bitstream encoder
 
9556
 */
 
9557
 
 
9558
struct duk_bitencoder_ctx {
 
9559
        duk_uint8_t *data;
 
9560
        duk_size_t offset;
 
9561
        duk_size_t length;
 
9562
        duk_uint32_t currval;
 
9563
        duk_small_int_t currbits;
 
9564
        duk_small_int_t truncated;
 
9565
};
 
9566
 
 
9567
/*
 
9568
 *  Externs and prototypes
 
9569
 */
 
9570
 
 
9571
extern duk_uint8_t duk_lc_digits[36];
 
9572
extern duk_uint8_t duk_uc_nybbles[16];
 
9573
 
 
9574
/* Note: assumes that duk_util_probe_steps size is 32 */
 
9575
extern duk_uint8_t duk_util_probe_steps[32];
 
9576
 
 
9577
duk_uint32_t duk_util_hashbytes(duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
 
9578
 
 
9579
duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
 
9580
 
 
9581
duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
 
9582
duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
 
9583
duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
 
9584
 
 
9585
void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
 
9586
void duk_be_finish(duk_bitencoder_ctx *ctx);
 
9587
 
 
9588
duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
 
9589
duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
 
9590
 
 
9591
#endif  /* DUK_UTIL_H_INCLUDED */
 
9592
 
 
9593
#line 1 "duk_unicode.h"
 
9594
/*
 
9595
 *  Unicode helpers
 
9596
 */
 
9597
 
 
9598
#ifndef DUK_UNICODE_H_INCLUDED
 
9599
#define DUK_UNICODE_H_INCLUDED
 
9600
 
 
9601
/*
 
9602
 *  UTF-8 / XUTF-8 / CESU-8 constants
 
9603
 */
 
9604
 
 
9605
#define DUK_UNICODE_MAX_XUTF8_LENGTH   7   /* up to 36 bit codepoints */
 
9606
#define DUK_UNICODE_MAX_CESU8_LENGTH   6   /* all codepoints up to U+10FFFF */
 
9607
 
 
9608
/*
 
9609
 *  Useful Unicode codepoints
 
9610
 *
 
9611
 *  Integer constants must be signed to avoid unexpected coercions
 
9612
 *  in comparisons.
 
9613
 */
 
9614
 
 
9615
#define DUK_UNICODE_CP_ZWNJ                   0x200cL  /* zero-width non-joiner */
 
9616
#define DUK_UNICODE_CP_ZWJ                    0x200dL  /* zero-width joiner */
 
9617
#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER  0xfffdL  /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
 
9618
 
 
9619
/*
 
9620
 *  ASCII character constants
 
9621
 *
 
9622
 *  C character literals like 'x' have a platform specific value and do
 
9623
 *  not match ASCII (UTF-8) values on e.g. EBCDIC platforms.  So, use
 
9624
 *  these (admittedly awkward) constants instead.  These constants must
 
9625
 *  also have signed values to avoid unexpected coercions in comparisons.
 
9626
 *
 
9627
 *  http://en.wikipedia.org/wiki/ASCII
 
9628
 */
 
9629
 
 
9630
#define DUK_ASC_NUL              0x00
 
9631
#define DUK_ASC_SOH              0x01
 
9632
#define DUK_ASC_STX              0x02
 
9633
#define DUK_ASC_ETX              0x03
 
9634
#define DUK_ASC_EOT              0x04
 
9635
#define DUK_ASC_ENQ              0x05
 
9636
#define DUK_ASC_ACK              0x06
 
9637
#define DUK_ASC_BEL              0x07
 
9638
#define DUK_ASC_BS               0x08
 
9639
#define DUK_ASC_HT               0x09
 
9640
#define DUK_ASC_LF               0x0a
 
9641
#define DUK_ASC_VT               0x0b
 
9642
#define DUK_ASC_FF               0x0c
 
9643
#define DUK_ASC_CR               0x0d
 
9644
#define DUK_ASC_SO               0x0e
 
9645
#define DUK_ASC_SI               0x0f
 
9646
#define DUK_ASC_DLE              0x10
 
9647
#define DUK_ASC_DC1              0x11
 
9648
#define DUK_ASC_DC2              0x12
 
9649
#define DUK_ASC_DC3              0x13
 
9650
#define DUK_ASC_DC4              0x14
 
9651
#define DUK_ASC_NAK              0x15
 
9652
#define DUK_ASC_SYN              0x16
 
9653
#define DUK_ASC_ETB              0x17
 
9654
#define DUK_ASC_CAN              0x18
 
9655
#define DUK_ASC_EM               0x19
 
9656
#define DUK_ASC_SUB              0x1a
 
9657
#define DUK_ASC_ESC              0x1b
 
9658
#define DUK_ASC_FS               0x1c
 
9659
#define DUK_ASC_GS               0x1d
 
9660
#define DUK_ASC_RS               0x1e
 
9661
#define DUK_ASC_US               0x1f
 
9662
#define DUK_ASC_SPACE            0x20
 
9663
#define DUK_ASC_EXCLAMATION      0x21
 
9664
#define DUK_ASC_DOUBLEQUOTE      0x22
 
9665
#define DUK_ASC_HASH             0x23
 
9666
#define DUK_ASC_DOLLAR           0x24
 
9667
#define DUK_ASC_PERCENT          0x25
 
9668
#define DUK_ASC_AMP              0x26
 
9669
#define DUK_ASC_SINGLEQUOTE      0x27
 
9670
#define DUK_ASC_LPAREN           0x28
 
9671
#define DUK_ASC_RPAREN           0x29
 
9672
#define DUK_ASC_STAR             0x2a
 
9673
#define DUK_ASC_PLUS             0x2b
 
9674
#define DUK_ASC_COMMA            0x2c
 
9675
#define DUK_ASC_MINUS            0x2d
 
9676
#define DUK_ASC_PERIOD           0x2e
 
9677
#define DUK_ASC_SLASH            0x2f
 
9678
#define DUK_ASC_0                0x30
 
9679
#define DUK_ASC_1                0x31
 
9680
#define DUK_ASC_2                0x32
 
9681
#define DUK_ASC_3                0x33
 
9682
#define DUK_ASC_4                0x34
 
9683
#define DUK_ASC_5                0x35
 
9684
#define DUK_ASC_6                0x36
 
9685
#define DUK_ASC_7                0x37
 
9686
#define DUK_ASC_8                0x38
 
9687
#define DUK_ASC_9                0x39
 
9688
#define DUK_ASC_COLON            0x3a
 
9689
#define DUK_ASC_SEMICOLON        0x3b
 
9690
#define DUK_ASC_LANGLE           0x3c
 
9691
#define DUK_ASC_EQUALS           0x3d
 
9692
#define DUK_ASC_RANGLE           0x3e
 
9693
#define DUK_ASC_QUESTION         0x3f
 
9694
#define DUK_ASC_ATSIGN           0x40
 
9695
#define DUK_ASC_UC_A             0x41
 
9696
#define DUK_ASC_UC_B             0x42
 
9697
#define DUK_ASC_UC_C             0x43
 
9698
#define DUK_ASC_UC_D             0x44
 
9699
#define DUK_ASC_UC_E             0x45
 
9700
#define DUK_ASC_UC_F             0x46
 
9701
#define DUK_ASC_UC_G             0x47
 
9702
#define DUK_ASC_UC_H             0x48
 
9703
#define DUK_ASC_UC_I             0x49
 
9704
#define DUK_ASC_UC_J             0x4a
 
9705
#define DUK_ASC_UC_K             0x4b
 
9706
#define DUK_ASC_UC_L             0x4c
 
9707
#define DUK_ASC_UC_M             0x4d
 
9708
#define DUK_ASC_UC_N             0x4e
 
9709
#define DUK_ASC_UC_O             0x4f
 
9710
#define DUK_ASC_UC_P             0x50
 
9711
#define DUK_ASC_UC_Q             0x51
 
9712
#define DUK_ASC_UC_R             0x52
 
9713
#define DUK_ASC_UC_S             0x53
 
9714
#define DUK_ASC_UC_T             0x54
 
9715
#define DUK_ASC_UC_U             0x55
 
9716
#define DUK_ASC_UC_V             0x56
 
9717
#define DUK_ASC_UC_W             0x57
 
9718
#define DUK_ASC_UC_X             0x58
 
9719
#define DUK_ASC_UC_Y             0x59
 
9720
#define DUK_ASC_UC_Z             0x5a
 
9721
#define DUK_ASC_LBRACKET         0x5b
 
9722
#define DUK_ASC_BACKSLASH        0x5c
 
9723
#define DUK_ASC_RBRACKET         0x5d
 
9724
#define DUK_ASC_CARET            0x5e
 
9725
#define DUK_ASC_UNDERSCORE       0x5f
 
9726
#define DUK_ASC_GRAVE            0x60
 
9727
#define DUK_ASC_LC_A             0x61
 
9728
#define DUK_ASC_LC_B             0x62
 
9729
#define DUK_ASC_LC_C             0x63
 
9730
#define DUK_ASC_LC_D             0x64
 
9731
#define DUK_ASC_LC_E             0x65
 
9732
#define DUK_ASC_LC_F             0x66
 
9733
#define DUK_ASC_LC_G             0x67
 
9734
#define DUK_ASC_LC_H             0x68
 
9735
#define DUK_ASC_LC_I             0x69
 
9736
#define DUK_ASC_LC_J             0x6a
 
9737
#define DUK_ASC_LC_K             0x6b
 
9738
#define DUK_ASC_LC_L             0x6c
 
9739
#define DUK_ASC_LC_M             0x6d
 
9740
#define DUK_ASC_LC_N             0x6e
 
9741
#define DUK_ASC_LC_O             0x6f
 
9742
#define DUK_ASC_LC_P             0x70
 
9743
#define DUK_ASC_LC_Q             0x71
 
9744
#define DUK_ASC_LC_R             0x72
 
9745
#define DUK_ASC_LC_S             0x73
 
9746
#define DUK_ASC_LC_T             0x74
 
9747
#define DUK_ASC_LC_U             0x75
 
9748
#define DUK_ASC_LC_V             0x76
 
9749
#define DUK_ASC_LC_W             0x77
 
9750
#define DUK_ASC_LC_X             0x78
 
9751
#define DUK_ASC_LC_Y             0x79
 
9752
#define DUK_ASC_LC_Z             0x7a
 
9753
#define DUK_ASC_LCURLY           0x7b
 
9754
#define DUK_ASC_PIPE             0x7c
 
9755
#define DUK_ASC_RCURLY           0x7d
 
9756
#define DUK_ASC_TILDE            0x7e
 
9757
#define DUK_ASC_DEL              0x7f
 
9758
 
 
9759
/*
 
9760
 *  Unicode tables
 
9761
 */
 
9762
 
 
9763
#ifdef DUK_USE_SOURCE_NONBMP
 
9764
/*
 
9765
 *  Automatically generated by extract_chars.py, do not edit!
 
9766
 */
 
9767
 
 
9768
extern const duk_uint8_t duk_unicode_ids_noa[797];
 
9769
#else
 
9770
/*
 
9771
 *  Automatically generated by extract_chars.py, do not edit!
 
9772
 */
 
9773
 
 
9774
extern const duk_uint8_t duk_unicode_ids_noabmp[614];
 
9775
#endif
 
9776
 
 
9777
#ifdef DUK_USE_SOURCE_NONBMP
 
9778
/*
 
9779
 *  Automatically generated by extract_chars.py, do not edit!
 
9780
 */
 
9781
 
 
9782
extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
 
9783
#else
 
9784
/*
 
9785
 *  Automatically generated by extract_chars.py, do not edit!
 
9786
 */
 
9787
 
 
9788
extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
 
9789
#endif
 
9790
 
 
9791
#ifdef DUK_USE_SOURCE_NONBMP
 
9792
/*
 
9793
 *  Automatically generated by extract_chars.py, do not edit!
 
9794
 */
 
9795
 
 
9796
extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
 
9797
#else
 
9798
/*
 
9799
 *  Automatically generated by extract_chars.py, do not edit!
 
9800
 */
 
9801
 
 
9802
extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
 
9803
#endif
 
9804
 
 
9805
/*
 
9806
 *  Automatically generated by extract_caseconv.py, do not edit!
 
9807
 */
 
9808
 
 
9809
extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
 
9810
extern const duk_uint8_t duk_unicode_caseconv_lc[616];
 
9811
 
 
9812
/*
 
9813
 *  Extern
 
9814
 */
 
9815
 
 
9816
/* duk_unicode_support.c */
 
9817
extern duk_uint8_t duk_unicode_xutf8_markers[7];
 
9818
extern duk_uint16_t duk_unicode_re_ranges_digit[2];
 
9819
extern duk_uint16_t duk_unicode_re_ranges_white[22];
 
9820
extern duk_uint16_t duk_unicode_re_ranges_wordchar[8];
 
9821
extern duk_uint16_t duk_unicode_re_ranges_not_digit[4];
 
9822
extern duk_uint16_t duk_unicode_re_ranges_not_white[24];
 
9823
extern duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
 
9824
 
 
9825
/*
 
9826
 *  Prototypes
 
9827
 */
 
9828
 
 
9829
duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
 
9830
duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
 
9831
duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
 
9832
duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp);
 
9833
duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end);
 
9834
duk_size_t duk_unicode_unvalidated_utf8_length(duk_uint8_t *data, duk_size_t blen);
 
9835
duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
 
9836
duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
 
9837
duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
 
9838
duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
 
9839
duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
 
9840
void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase);
 
9841
duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
 
9842
duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
 
9843
 
 
9844
#endif  /* DUK_UNICODE_H_INCLUDED */
 
9845
 
 
9846
#line 1 "duk_json.h"
 
9847
/*
 
9848
 *  Defines for JSON, especially duk_bi_json.c.
 
9849
 */
 
9850
 
 
9851
#ifndef DUK_JSON_H_INCLUDED
 
9852
#define DUK_JSON_H_INCLUDED
 
9853
 
 
9854
/* Object/array recursion limit (to protect C stack) */
 
9855
#if defined(DUK_USE_DEEP_C_STACK)
 
9856
#define DUK_JSON_ENC_RECURSION_LIMIT          1000
 
9857
#define DUK_JSON_DEC_RECURSION_LIMIT          1000
 
9858
#else
 
9859
#define DUK_JSON_ENC_RECURSION_LIMIT          100
 
9860
#define DUK_JSON_DEC_RECURSION_LIMIT          100
 
9861
#endif
 
9862
 
 
9863
/* Encoding/decoding flags */
 
9864
#define DUK_JSON_FLAG_ASCII_ONLY          (1 << 0)  /* escape any non-ASCII characters */
 
9865
#define DUK_JSON_FLAG_AVOID_KEY_QUOTES    (1 << 1)  /* avoid key quotes when key is an ASCII Identifier */
 
9866
#define DUK_JSON_FLAG_EXT_CUSTOM          (1 << 2)  /* extended types: custom encoding */
 
9867
#define DUK_JSON_FLAG_EXT_COMPATIBLE      (1 << 3)  /* extended types: compatible encoding */
 
9868
 
 
9869
/* How much stack to require on entry to object/array encode */
 
9870
#define DUK_JSON_ENC_REQSTACK                 32
 
9871
 
 
9872
/* How much stack to require on entry to object/array decode */
 
9873
#define DUK_JSON_DEC_REQSTACK                 32
 
9874
 
 
9875
/* Encoding state.  Heap object references are all borrowed. */
 
9876
typedef struct {
 
9877
        duk_hthread *thr;
 
9878
        duk_hbuffer_dynamic *h_buf;
 
9879
        duk_hobject *h_replacer;     /* replacer function */
 
9880
        duk_hstring *h_gap;          /* gap (if empty string, NULL) */
 
9881
        duk_hstring *h_indent;       /* current indent (if gap is NULL, this is NULL) */
 
9882
        int idx_proplist;            /* explicit PropertyList */
 
9883
        int idx_loop;                /* valstack index of loop detection object */
 
9884
        int flags;
 
9885
        int flag_ascii_only;
 
9886
        int flag_avoid_key_quotes;
 
9887
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
9888
        int flag_ext_custom;
 
9889
        int flag_ext_compatible;
 
9890
#endif
 
9891
        int recursion_depth;
 
9892
        int recursion_limit;
 
9893
        int mask_for_undefined;      /* type bit mask: types which certainly produce 'undefined' */
 
9894
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
9895
        int stridx_custom_undefined;
 
9896
        int stridx_custom_nan;
 
9897
        int stridx_custom_neginf;
 
9898
        int stridx_custom_posinf;
 
9899
        int stridx_custom_function;
 
9900
#endif
 
9901
} duk_json_enc_ctx;
 
9902
 
 
9903
typedef struct {
 
9904
        duk_hthread *thr;
 
9905
        duk_uint8_t *p;
 
9906
        duk_uint8_t *p_end;
 
9907
        int idx_reviver;
 
9908
        int flags;
 
9909
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
9910
        int flag_ext_custom;
 
9911
        int flag_ext_compatible;
 
9912
#endif
 
9913
        int recursion_depth;
 
9914
        int recursion_limit;
 
9915
} duk_json_dec_ctx;
 
9916
 
 
9917
#endif  /* DUK_JSON_H_INCLUDED */
 
9918
 
 
9919
#line 1 "duk_js.h"
 
9920
/*
 
9921
 *  Ecmascript execution, support primitives.
 
9922
 */
 
9923
 
 
9924
#ifndef DUK_JS_H_INCLUDED
 
9925
#define DUK_JS_H_INCLUDED
 
9926
 
 
9927
/* Flags for call handling. */
 
9928
#define DUK_CALL_FLAG_PROTECTED              (1 << 0)  /* duk_handle_call: call is protected */
 
9929
#define DUK_CALL_FLAG_IGNORE_RECLIMIT        (1 << 1)  /* duk_handle_call: call ignores C recursion limit (for errhandler calls) */
 
9930
#define DUK_CALL_FLAG_CONSTRUCTOR_CALL       (1 << 2)  /* duk_handle_call: constructor call (i.e. called as 'new Foo()') */
 
9931
#define DUK_CALL_FLAG_IS_RESUME              (1 << 3)  /* duk_handle_ecma_call_setup: setup for a resume() */
 
9932
#define DUK_CALL_FLAG_IS_TAILCALL            (1 << 4)  /* duk_handle_ecma_call_setup: setup for a tailcall */
 
9933
#define DUK_CALL_FLAG_DIRECT_EVAL            (1 << 5)  /* call is a direct eval call */
 
9934
 
 
9935
/* Flags for duk_js_equals_helper(). */
 
9936
#define DUK_EQUALS_FLAG_SAMEVALUE            (1 << 0)  /* use SameValue instead of non-strict equality */
 
9937
#define DUK_EQUALS_FLAG_STRICT               (1 << 1)  /* use strict equality instead of non-strict equality */
 
9938
 
 
9939
/* Flags for duk_js_compare_helper(). */
 
9940
#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST     (1 << 0)  /* eval left argument first */
 
9941
#define DUK_COMPARE_FLAG_NEGATE              (1 << 1)  /* negate result */
 
9942
 
 
9943
/* conversions, coercions, comparison, etc */
 
9944
int duk_js_toboolean(duk_tval *tv);
 
9945
double duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
 
9946
double duk_js_tointeger_number(double x);
 
9947
double duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
 
9948
duk_uint32_t duk_js_touint32_number(double x);
 
9949
duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
 
9950
duk_int32_t duk_js_toint32_number(double x);
 
9951
duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
 
9952
duk_uint16_t duk_js_touint16_number(double x);
 
9953
duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
 
9954
duk_small_int_t duk_js_to_arrayindex_raw_string(duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_idx);
 
9955
duk_uint32_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
 
9956
int duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
 
9957
int duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
 
9958
int duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
 
9959
int duk_js_lessthan(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9960
int duk_js_greaterthan(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9961
int duk_js_lessthanorequal(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9962
int duk_js_greaterthanorequal(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9963
int duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9964
int duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
 
9965
duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
 
9966
 
 
9967
#define duk_js_equals(thr,tv_x,tv_y) \
 
9968
        duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
 
9969
#define duk_js_strict_equals(tv_x,tv_y) \
 
9970
        duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
 
9971
#define duk_js_samevalue(tv_x,tv_y) \
 
9972
        duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
 
9973
 
 
9974
/* E5 Sections 11.8.1, 11.8.5; x < y */
 
9975
#define duk_js_lessthan(thr,tv_x,tv_y) \
 
9976
        duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
 
9977
 
 
9978
/* E5 Sections 11.8.2, 11.8.5; x > y  -->  y < x */
 
9979
#define duk_js_greaterthan(thr,tv_x,tv_y) \
 
9980
        duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
 
9981
 
 
9982
/* E5 Sections 11.8.3, 11.8.5; x <= y  -->  not (x > y)  -->  not (y < x) */
 
9983
#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
 
9984
        duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
 
9985
 
 
9986
/* E5 Sections 11.8.4, 11.8.5; x >= y  -->  not (x < y) */
 
9987
#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
 
9988
        duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
 
9989
 
 
9990
/* identifiers and environment handling */
 
9991
int duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, int throw_flag);
 
9992
int duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, int throw_flag);
 
9993
void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, int strict);
 
9994
void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, int strict);
 
9995
int duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
 
9996
int duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
 
9997
int duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, int prop_flags, int is_func_decl);
 
9998
void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
 
9999
void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, int regbase);
 
10000
duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_uint32_t reg_bottom);
 
10001
void duk_js_push_closure(duk_hthread *thr,
 
10002
                         duk_hcompiledfunction *fun_temp,
 
10003
                         duk_hobject *outer_var_env,
 
10004
                         duk_hobject *outer_lex_env);
 
10005
 
 
10006
/* call handling */
 
10007
int duk_handle_call(duk_hthread *thr,
 
10008
                    int num_stack_args,
 
10009
                    int call_flags);
 
10010
int duk_handle_safe_call(duk_hthread *thr,
 
10011
                         duk_safe_call_function func,
 
10012
                         int num_stack_args,
 
10013
                         int num_stack_res);
 
10014
void duk_handle_ecma_call_setup(duk_hthread *thr,
 
10015
                                int num_stack_args,
 
10016
                                int call_flags);
 
10017
 
 
10018
/* bytecode execution */
 
10019
void duk_js_execute_bytecode(duk_hthread *entry_thread);
 
10020
 
 
10021
#endif  /* DUK_JS_H_INCLUDED */
 
10022
 
 
10023
#line 1 "duk_numconv.h"
 
10024
#ifndef DUK_NUMCONV_H_INCLUDED
 
10025
#define DUK_NUMCONV_H_INCLUDED
 
10026
 
 
10027
/*
 
10028
 *  Number-to-string conversion.  The semantics of these is very tightly
 
10029
 *  bound with the Ecmascript semantics required for call sites.
 
10030
 */
 
10031
 
 
10032
/* Output a specified number of digits instead of using the shortest
 
10033
 * form.  Used for toPrecision() and toFixed().
 
10034
 */
 
10035
#define DUK_N2S_FLAG_FIXED_FORMAT         (1 << 0)
 
10036
 
 
10037
/* Force exponential format.  Used for toExponential(). */
 
10038
#define DUK_N2S_FLAG_FORCE_EXP            (1 << 1)
 
10039
 
 
10040
/* If number would need zero padding (for whole number part), use
 
10041
 * exponential format instead.  E.g. if input number is 12300, 3
 
10042
 * digits are generated ("123"), output "1.23e+4" instead of "12300".
 
10043
 * Used for toPrecision().
 
10044
 */
 
10045
#define DUK_N2S_FLAG_NO_ZERO_PAD          (1 << 2)
 
10046
 
 
10047
/* Digit count indicates number of fractions (i.e. an absolute
 
10048
 * digit index instead of a relative one).  Used together with
 
10049
 * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
 
10050
 */
 
10051
#define DUK_N2S_FLAG_FRACTION_DIGITS      (1 << 3)
 
10052
 
 
10053
/*
 
10054
 *  String-to-number conversion
 
10055
 */
 
10056
 
 
10057
/* Maximum exponent value when parsing numbers.  This is not strictly
 
10058
 * compliant as there should be no upper limit, but as we parse the
 
10059
 * exponent without a bigint, impose some limit.
 
10060
 */
 
10061
#define DUK_S2N_MAX_EXPONENT              1000000000
 
10062
 
 
10063
/* Trim white space (= allow leading and trailing whitespace) */
 
10064
#define DUK_S2N_FLAG_TRIM_WHITE           (1 << 0)
 
10065
 
 
10066
/* Allow exponent */
 
10067
#define DUK_S2N_FLAG_ALLOW_EXP            (1 << 1)
 
10068
 
 
10069
/* Allow trailing garbage (e.g. treat "123foo" as "123) */
 
10070
#define DUK_S2N_FLAG_ALLOW_GARBAGE        (1 << 2)
 
10071
 
 
10072
/* Allow leading plus sign */
 
10073
#define DUK_S2N_FLAG_ALLOW_PLUS           (1 << 3)
 
10074
 
 
10075
/* Allow leading minus sign */
 
10076
#define DUK_S2N_FLAG_ALLOW_MINUS          (1 << 4)
 
10077
 
 
10078
/* Allow 'Infinity' */
 
10079
#define DUK_S2N_FLAG_ALLOW_INF            (1 << 5)
 
10080
 
 
10081
/* Allow fraction part */
 
10082
#define DUK_S2N_FLAG_ALLOW_FRAC           (1 << 6)
 
10083
 
 
10084
/* Allow naked fraction (e.g. ".123") */
 
10085
#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC     (1 << 7)
 
10086
 
 
10087
/* Allow empty fraction (e.g. "123.") */
 
10088
#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC     (1 << 8)
 
10089
 
 
10090
/* Allow empty string to be interpreted as 0 */
 
10091
#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO  (1 << 9)
 
10092
 
 
10093
/* Allow leading zeroes (e.g. "0123" -> "123") */
 
10094
#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO   (1 << 10)
 
10095
 
 
10096
/* Allow automatic detection of hex base ("0x" or "0X" prefix),
 
10097
 * overrides radix argument and forces integer mode.
 
10098
 */
 
10099
#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT   (1 << 11)
 
10100
 
 
10101
/* Allow automatic detection of octal base, overrides radix
 
10102
 * argument and forces integer mode.
 
10103
 */
 
10104
#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT   (1 << 12)
 
10105
 
 
10106
/*
 
10107
 *  Prototypes
 
10108
 */
 
10109
 
 
10110
void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
 
10111
void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
 
10112
 
 
10113
#endif  /* DUK_NUMCONV_H_INCLUDED */
 
10114
 
 
10115
#line 1 "duk_bi_protos.h"
 
10116
/*
 
10117
 *  Prototypes for all built-in functions.
 
10118
 */
 
10119
 
 
10120
#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
 
10121
#define DUK_BUILTIN_PROTOS_H_INCLUDED
 
10122
 
 
10123
/* Buffer size needed for duk_bi_date_format_timeval().
 
10124
 * Accurate value is 32 + 1 for NUL termination:
 
10125
 *   >>> len('+123456-01-23T12:34:56.123+12:34')
 
10126
 *   32
 
10127
 * Include additional space to be safe.
 
10128
 */
 
10129
#define  DUK_BI_DATE_ISO8601_BUFSIZE  48
 
10130
 
 
10131
/* Buffer size for "short log message" which use a heap-level pre-allocated
 
10132
 * dynamic buffer to reduce memory churn.
 
10133
 */
 
10134
#define  DUK_BI_LOGGER_SHORT_MSG_LIMIT  256
 
10135
 
 
10136
duk_ret_t duk_bi_array_constructor(duk_context *ctx);
 
10137
duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
 
10138
duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
 
10139
duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
 
10140
duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
 
10141
duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
 
10142
duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
 
10143
duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
 
10144
duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
 
10145
duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
 
10146
duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
 
10147
duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
 
10148
duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
 
10149
duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
 
10150
duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
 
10151
duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
 
10152
 
 
10153
duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
 
10154
duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
 
10155
 
 
10156
duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
 
10157
duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
 
10158
 
 
10159
duk_ret_t duk_bi_date_constructor(duk_context *ctx);
 
10160
duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
 
10161
duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
 
10162
duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
 
10163
duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
 
10164
duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
 
10165
duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
 
10166
duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
 
10167
duk_ret_t duk_bi_date_prototype_get_time(duk_context *ctx);
 
10168
duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
 
10169
duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
 
10170
duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
 
10171
/* Helpers exposed for internal use */
 
10172
duk_double_t duk_bi_date_get_now(duk_context *ctx);
 
10173
void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
 
10174
 
 
10175
duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
 
10176
duk_ret_t duk_bi_duktape_object_line(duk_context *ctx);
 
10177
duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
 
10178
duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
 
10179
duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
 
10180
duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
 
10181
duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
 
10182
duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
 
10183
 
 
10184
duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
 
10185
duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
 
10186
duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
 
10187
duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
 
10188
duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
 
10189
duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
 
10190
duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx);
 
10191
 
 
10192
duk_ret_t duk_bi_function_constructor(duk_context *ctx);
 
10193
duk_ret_t duk_bi_function_prototype(duk_context *ctx);
 
10194
duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
 
10195
duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
 
10196
duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
 
10197
duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
 
10198
 
 
10199
duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
 
10200
duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
 
10201
duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
 
10202
duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
 
10203
duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
 
10204
duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
 
10205
duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
 
10206
duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
 
10207
duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
 
10208
#ifdef DUK_USE_SECTION_B
 
10209
duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
 
10210
duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
 
10211
#endif
 
10212
#ifdef DUK_USE_BROWSER_LIKE
 
10213
duk_ret_t duk_bi_global_object_print(duk_context *ctx);
 
10214
duk_ret_t duk_bi_global_object_alert(duk_context *ctx);
 
10215
#endif
 
10216
 
 
10217
/* FIXME: typing */
 
10218
void duk_bi_json_parse_helper(duk_context *ctx,
 
10219
                              int idx_value,
 
10220
                              int idx_reviver,
 
10221
                              int flags);
 
10222
void duk_bi_json_stringify_helper(duk_context *ctx,
 
10223
                                  int idx_value,
 
10224
                                  int idx_replacer,
 
10225
                                  int idx_space,
 
10226
                                  int flags);
 
10227
duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
 
10228
duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
 
10229
 
 
10230
duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
 
10231
duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
 
10232
duk_ret_t duk_bi_math_object_max(duk_context *ctx);
 
10233
duk_ret_t duk_bi_math_object_min(duk_context *ctx);
 
10234
duk_ret_t duk_bi_math_object_random(duk_context *ctx);
 
10235
 
 
10236
duk_ret_t duk_bi_number_constructor(duk_context *ctx);
 
10237
duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
 
10238
duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
 
10239
duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
 
10240
duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
 
10241
duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
 
10242
duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
 
10243
 
 
10244
duk_ret_t duk_bi_object_constructor(duk_context *ctx);
 
10245
duk_ret_t duk_bi_object_constructor_get_prototype_of(duk_context *ctx);
 
10246
duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
 
10247
duk_ret_t duk_bi_object_constructor_get_own_property_names(duk_context *ctx);
 
10248
duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
 
10249
duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
 
10250
duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
 
10251
duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
 
10252
duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
 
10253
duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
 
10254
duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
 
10255
duk_ret_t duk_bi_object_constructor_keys(duk_context *ctx);
 
10256
duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
 
10257
duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
 
10258
duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
 
10259
duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
 
10260
duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
 
10261
duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
 
10262
 
 
10263
duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
 
10264
duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
 
10265
 
 
10266
duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
 
10267
duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
 
10268
duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
 
10269
duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
 
10270
 
 
10271
duk_ret_t duk_bi_string_constructor(duk_context *ctx);
 
10272
duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
 
10273
duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
 
10274
duk_ret_t duk_bi_string_prototype_value_of(duk_context *ctx);
 
10275
duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
 
10276
duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
 
10277
duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
 
10278
duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
 
10279
duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
 
10280
duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
 
10281
duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
 
10282
duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
 
10283
duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
 
10284
duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
 
10285
duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
 
10286
duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
 
10287
duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
 
10288
#ifdef DUK_USE_SECTION_B
 
10289
duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
 
10290
#endif
 
10291
duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
 
10292
duk_ret_t duk_bi_thread_resume(duk_context *ctx);
 
10293
duk_ret_t duk_bi_thread_yield(duk_context *ctx);
 
10294
duk_ret_t duk_bi_thread_current(duk_context *ctx);
 
10295
 
 
10296
duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
 
10297
duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
 
10298
duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
 
10299
duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
 
10300
 
 
10301
duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
 
10302
 
 
10303
#endif  /* DUK_BUILTIN_PROTOS_H_INCLUDED */
 
10304
 
 
10305
#line 1 "duk_selftest.h"
 
10306
/*
 
10307
 *  Selftest code
 
10308
 */
 
10309
 
 
10310
#ifndef DUK_SELFTEST_H_INCLUDED
 
10311
#define DUK_SELFTEST_H_INCLUDED
 
10312
 
 
10313
void duk_selftest_run_tests(void);
 
10314
 
 
10315
#endif  /* DUK_SELFTEST_H_INCLUDED */
 
10316
#line 70 "duk_internal.h"
 
10317
 
 
10318
#endif  /* DUK_INTERNAL_H_INCLUDED */
 
10319
 
 
10320
#line 1 "duk_alloc_default.c"
 
10321
/*
 
10322
 *  Default allocation functions.
 
10323
 *
 
10324
 *  Assumes behavior such as malloc allowing zero size, yielding
 
10325
 *  a NULL or a unique pointer which is a no-op for free.
 
10326
 */
 
10327
 
 
10328
/* include removed: duk_internal.h */
 
10329
 
 
10330
void *duk_default_alloc_function(void *udata, size_t size) {
 
10331
        void *res;
 
10332
        DUK_UNREF(udata);
 
10333
        res = DUK_ANSI_MALLOC(size);
 
10334
        DUK_DDDPRINT("default alloc function: %d -> %p",
 
10335
                     (int) size, (void *) res);
 
10336
        return res;
 
10337
}
 
10338
 
 
10339
void *duk_default_realloc_function(void *udata, void *ptr, size_t newsize) {
 
10340
        void *res;
 
10341
        DUK_UNREF(udata);
 
10342
        res = DUK_ANSI_REALLOC(ptr, newsize);
 
10343
        DUK_DDDPRINT("default realloc function: %p %d -> %p", 
 
10344
                     (void *) ptr, (int) newsize, (void *) res);
 
10345
        return res;
 
10346
}
 
10347
 
 
10348
void duk_default_free_function(void *udata, void *ptr) {
 
10349
        DUK_DDDPRINT("default free function: %p", (void *) ptr);
 
10350
        DUK_UNREF(udata);
 
10351
        DUK_ANSI_FREE(ptr);
 
10352
}
 
10353
#line 1 "duk_alloc_torture.c"
 
10354
/*
 
10355
 *  Torture allocation functions.
 
10356
 *
 
10357
 *  Provides various debugging features:
 
10358
 *
 
10359
 *    - Wraps allocations with "buffer zones" which are checked on free
 
10360
 *    - Overwrites freed memory with garbage (not zero)
 
10361
 *    - Debug prints memory usage info after every alloc/realloc/free
 
10362
 *
 
10363
 *  Can be left out of a standard compilation.
 
10364
 */
 
10365
 
 
10366
/* include removed: duk_internal.h */
 
10367
 
 
10368
/* FIXME: unimplemented */
 
10369
 
 
10370
void *duk_torture_alloc_function(void *udata, size_t size) {
 
10371
        void *res;
 
10372
        DUK_UNREF(udata);
 
10373
        res = DUK_ANSI_MALLOC(size);
 
10374
        DUK_DDDPRINT("torture alloc function: %d -> %p",
 
10375
                     (int) size, (void *) res);
 
10376
        return res;
 
10377
}
 
10378
 
 
10379
void *duk_torture_realloc_function(void *udata, void *ptr, size_t newsize) {
 
10380
        void *res;
 
10381
        DUK_UNREF(udata);
 
10382
        res = DUK_ANSI_REALLOC(ptr, newsize);
 
10383
        DUK_DDDPRINT("torture realloc function: %p %d -> %p", 
 
10384
                     (void *) ptr, (int) newsize, (void *) res);
 
10385
        return res;
 
10386
}
 
10387
 
 
10388
void duk_torture_free_function(void *udata, void *ptr) {
 
10389
        DUK_DDDPRINT("torture free function: %p", (void *) ptr);
 
10390
        DUK_UNREF(udata);
 
10391
        DUK_ANSI_FREE(ptr);
 
10392
}
 
10393
#line 1 "duk_api.c"
 
10394
/*
 
10395
 *  API calls not falling into other categories.
 
10396
 *
 
10397
 *  Also contains internal functions (such as duk_get_tval()), defined
 
10398
 *  in duk_api_internal.h, with semantics similar to the public API.
 
10399
 */
 
10400
 
 
10401
/* FIXME: repetition of stack pre-checks -> helper or macro or inline */
 
10402
/* FIXME: shared api error strings, and perhaps even throw code for rare cases? */
 
10403
 
 
10404
/* include removed: duk_internal.h */
 
10405
 
 
10406
/*
 
10407
 *  Global state for working around missing variadic macros
 
10408
 */
 
10409
 
 
10410
#ifndef DUK_USE_VARIADIC_MACROS
 
10411
const char *duk_api_global_filename = NULL;
 
10412
int duk_api_global_line = 0;
 
10413
#endif
 
10414
 
 
10415
/*
 
10416
 *  Helpers
 
10417
 */
 
10418
 
 
10419
static int duk__api_coerce_d2i(double d) {
 
10420
        /*
 
10421
         *  Special cases like NaN and +/- Infinity are handled explicitly
 
10422
         *  because a plain C coercion from double to int handles these cases
 
10423
         *  in undesirable ways.  For instance, NaN may coerce to INT_MIN
 
10424
         *  (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
 
10425
         *
 
10426
         *  This double-to-int coercion differs from ToInteger() because it
 
10427
         *  has a finite range (ToInteger() allows e.g. +/- Infinity).  It
 
10428
         *  also differs from ToInt32() because the INT_MIN/INT_MAX clamping
 
10429
         *  depends on the size of the int type on the platform.  In particular,
 
10430
         *  on platforms with a 64-bit int type, the full range is allowed.
 
10431
         */
 
10432
 
 
10433
        if (DUK_FPCLASSIFY(d) == DUK_FP_NAN) {
 
10434
                return 0;
 
10435
        } else if (d < INT_MIN) {
 
10436
                /* covers -Infinity */
 
10437
                return INT_MIN;
 
10438
        } else if (d > INT_MAX) {
 
10439
                /* covers +Infinity */
 
10440
                return INT_MAX;
 
10441
        } else {
 
10442
                /* coerce towards zero */
 
10443
                return (int) d;
 
10444
        }
 
10445
}
 
10446
 
 
10447
/*
 
10448
 *  Stack indexes and stack size management
 
10449
 */
 
10450
 
 
10451
int duk_normalize_index(duk_context *ctx, int index) {
 
10452
        duk_hthread *thr = (duk_hthread *) ctx;
 
10453
        duk_tval *tv;
 
10454
 
 
10455
        DUK_ASSERT(ctx != NULL);
 
10456
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
10457
 
 
10458
        if (index < 0) {
 
10459
                if (index == DUK_INVALID_INDEX) {
 
10460
                        goto fail;
 
10461
                }
 
10462
                tv = thr->valstack_top + index;
 
10463
                DUK_ASSERT(tv < thr->valstack_top);
 
10464
                if (tv < thr->valstack_bottom) {
 
10465
                        goto fail;
 
10466
                }
 
10467
        } else {
 
10468
                tv = thr->valstack_bottom + index;
 
10469
                DUK_ASSERT(tv >= thr->valstack_bottom);
 
10470
                if (tv >= thr->valstack_top) {
 
10471
                        goto fail;
 
10472
                }
 
10473
        }
 
10474
 
 
10475
        DUK_ASSERT((int) (tv - thr->valstack_bottom) >= 0);
 
10476
        return (int) (tv - thr->valstack_bottom);
 
10477
 
 
10478
 fail:
 
10479
        return DUK_INVALID_INDEX;
 
10480
}
 
10481
 
 
10482
int duk_require_normalize_index(duk_context *ctx, int index) {
 
10483
        duk_hthread *thr = (duk_hthread *) ctx;
 
10484
        int ret;
 
10485
 
 
10486
        DUK_ASSERT(ctx != NULL);
 
10487
 
 
10488
        ret = duk_normalize_index(ctx, index);
 
10489
        if (ret < 0) {
 
10490
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid index: %d", index);
 
10491
        }
 
10492
        return ret;
 
10493
}
 
10494
 
 
10495
int duk_is_valid_index(duk_context *ctx, int index) {
 
10496
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
10497
        return (duk_normalize_index(ctx, index) >= 0);
 
10498
}
 
10499
 
 
10500
void duk_require_valid_index(duk_context *ctx, int index) {
 
10501
        duk_hthread *thr = (duk_hthread *) ctx;
 
10502
 
 
10503
        DUK_ASSERT(ctx != NULL);
 
10504
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
10505
 
 
10506
        if (duk_normalize_index(ctx, index) < 0) {
 
10507
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid index: %d", index);
 
10508
        }
 
10509
}
 
10510
 
 
10511
int duk_get_top(duk_context *ctx) {
 
10512
        duk_hthread *thr = (duk_hthread *) ctx;
 
10513
 
 
10514
        DUK_ASSERT(ctx != NULL);
 
10515
 
 
10516
        return (int) (thr->valstack_top - thr->valstack_bottom);
 
10517
}
 
10518
 
 
10519
/* set stack top within currently allocated range, but don't reallocate */
 
10520
void duk_set_top(duk_context *ctx, int index) {
 
10521
        duk_hthread *thr = (duk_hthread *) ctx;
 
10522
        duk_tval *tv_new_top;
 
10523
 
 
10524
        DUK_ASSERT(ctx != NULL);
 
10525
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
10526
 
 
10527
        /* FIXME: the pointer arithmetic here is not safe on a 32-bit platform,
 
10528
         * as it may wrap.  For instance, with 8-byte values, the index 0x20000000
 
10529
         * will wrap and be equivalent to index 0; with 12-byte values, the index
 
10530
         * 0x15555556 will wrap to +8 bytes and does not even wrap evenly to a
 
10531
         * duk_tval boundary!  A correct check would first impose a min/max index
 
10532
         * which guarantees that there is only one "round" of wrapping at most,
 
10533
         * and then wrapping needs to be detected because we don't want the value
 
10534
         * stack to be wrapped around end-of-memory.
 
10535
         */
 
10536
 
 
10537
        if (index < 0) {
 
10538
                if (index == DUK_INVALID_INDEX) {
 
10539
                        goto invalid_index;
 
10540
                }
 
10541
                tv_new_top = thr->valstack_top + index;
 
10542
        } else {
 
10543
                /* may be higher than valstack_top, but not higher than
 
10544
                 * allocated stack
 
10545
                 */
 
10546
                tv_new_top = thr->valstack_bottom + index;
 
10547
        }
 
10548
 
 
10549
        /* Check both ends: for extreme values the pointer arithmetic may wrap.
 
10550
         * The check doesn't detect wrapping so it's technically incorrect.
 
10551
         */
 
10552
        if (tv_new_top < thr->valstack_bottom) {
 
10553
                goto invalid_index;
 
10554
        }
 
10555
        if (tv_new_top > thr->valstack_end) {
 
10556
                goto invalid_index;
 
10557
        }
 
10558
 
 
10559
        if (tv_new_top >= thr->valstack_top) {
 
10560
                /* no pointer stability issues when increasing stack size */
 
10561
                while (thr->valstack_top < tv_new_top) {
 
10562
                        /* no need to decref previous or new value */
 
10563
                        DUK_ASSERT(DUK_TVAL_IS_UNDEFINED_UNUSED(thr->valstack_top));
 
10564
                        DUK_TVAL_SET_UNDEFINED_ACTUAL(thr->valstack_top);
 
10565
                        thr->valstack_top++;
 
10566
                }
 
10567
        } else {
 
10568
                /* each DECREF potentially invalidates valstack pointers, careful */
 
10569
                ptrdiff_t pdiff = ((char *) thr->valstack_top) - ((char *) tv_new_top);  /* byte diff (avoid shift/div) */
 
10570
 
 
10571
                /* FIXME: inlined DECREF macro would be nice here: no NULL check,
 
10572
                 * refzero queueing but no refzero algorithm run (= no pointer
 
10573
                 * instability), inline code.
 
10574
                 */
 
10575
        
 
10576
                while (pdiff > 0) {
 
10577
                        duk_tval tv_tmp;
 
10578
                        duk_tval *tv;
 
10579
 
 
10580
                        thr->valstack_top--;
 
10581
                        tv = thr->valstack_top;
 
10582
                        DUK_ASSERT(tv >= thr->valstack_bottom);
 
10583
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
10584
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
10585
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
10586
 
 
10587
                        pdiff -= sizeof(duk_tval);
 
10588
                }
 
10589
        }
 
10590
        return;
 
10591
 
 
10592
 invalid_index:
 
10593
        DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid index: %d", index);
 
10594
}
 
10595
 
 
10596
int duk_get_top_index(duk_context *ctx) {
 
10597
        duk_hthread *thr = (duk_hthread *) ctx;
 
10598
        int ret;
 
10599
 
 
10600
        DUK_ASSERT(ctx != NULL);
 
10601
 
 
10602
        ret = ((int) (thr->valstack_top - thr->valstack_bottom)) - 1;
 
10603
        if (ret < 0) {
 
10604
                /* Return invalid index; if caller uses this without checking
 
10605
                 * in another API call, the index will never (practically)
 
10606
                 * map to a valid stack entry.
 
10607
                 */
 
10608
                return DUK_INVALID_INDEX;
 
10609
        }
 
10610
        return ret;
 
10611
}
 
10612
 
 
10613
int duk_require_top_index(duk_context *ctx) {
 
10614
        duk_hthread *thr = (duk_hthread *) ctx;
 
10615
        int ret;
 
10616
 
 
10617
        DUK_ASSERT(ctx != NULL);
 
10618
 
 
10619
        ret = ((int) (thr->valstack_top - thr->valstack_bottom)) - 1;
 
10620
        if (ret < 0) {
 
10621
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid index");
 
10622
        }
 
10623
        return ret;
 
10624
}
 
10625
 
 
10626
/* FIXME: perhaps refactor this to allow caller to specify some parameters, or
 
10627
 * at least a 'compact' flag which skips any spare or round-up .. useful for
 
10628
 * emergency gc.
 
10629
 */
 
10630
 
 
10631
/* Resize valstack, with careful recomputation of all pointers.
 
10632
 * Must also work if ALL pointers are NULL.
 
10633
 *
 
10634
 * Note: this is very tricky because the valstack realloc may
 
10635
 * cause a mark-and-sweep, which may run finalizers.  Running
 
10636
 * finalizers may resize the valstack recursively.  So, after
 
10637
 * realloc returns, we know that the valstack "top" should still
 
10638
 * be the same (there should not be live values above the "top"),
 
10639
 * but its underlying size may have changed.
 
10640
 */
 
10641
static int duk__resize_valstack(duk_context *ctx, size_t new_size) {
 
10642
        duk_hthread *thr = (duk_hthread *) ctx;
 
10643
        ptrdiff_t old_bottom_offset;
 
10644
        ptrdiff_t old_top_offset;
 
10645
        ptrdiff_t old_end_offset_post;
 
10646
#ifdef DUK_USE_DEBUG
 
10647
        ptrdiff_t old_end_offset_pre;
 
10648
        duk_tval *old_valstack_pre;
 
10649
        duk_tval *old_valstack_post;
 
10650
#endif
 
10651
        duk_tval *new_valstack;
 
10652
        duk_tval *p;
 
10653
        duk_size_t new_alloc_size;
 
10654
 
 
10655
        DUK_ASSERT(ctx != NULL);
 
10656
        DUK_ASSERT(thr != NULL);
 
10657
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
10658
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
10659
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
10660
        DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size);  /* can't resize below 'top' */
 
10661
 
 
10662
        /* get pointer offsets for tweaking below */
 
10663
        old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
 
10664
        old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
 
10665
#ifdef DUK_USE_DEBUG
 
10666
        old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack));  /* not very useful, used for debugging */
 
10667
        old_valstack_pre = thr->valstack;
 
10668
#endif
 
10669
 
 
10670
        /* allocate a new valstack
 
10671
         *
 
10672
         * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
 
10673
         * invalidate the original thr->valstack base pointer inside the realloc
 
10674
         * process.  See doc/memory-management.txt.
 
10675
         */
 
10676
 
 
10677
        new_alloc_size = sizeof(duk_tval) * new_size;
 
10678
        new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
 
10679
        if (!new_valstack) {
 
10680
                DUK_DPRINT("failed to resize valstack to %d entries (%d bytes)",
 
10681
                           new_size, new_alloc_size);
 
10682
                return 0;
 
10683
        }
 
10684
 
 
10685
        /* Note: the realloc may have triggered a mark-and-sweep which may
 
10686
         * have resized our valstack internally.  However, the mark-and-sweep
 
10687
         * MUST NOT leave the stack bottom/top in a different state.  Particular
 
10688
         * assumptions and facts:
 
10689
         *
 
10690
         *   - The thr->valstack pointer may be different after realloc,
 
10691
         *     and the offset between thr->valstack_end <-> thr->valstack
 
10692
         *     may have changed.
 
10693
         *   - The offset between thr->valstack_bottom <-> thr->valstack
 
10694
         *     and thr->valstack_top <-> thr->valstack MUST NOT have changed,
 
10695
         *     because mark-and-sweep must adhere to a strict stack policy.
 
10696
         *     In other words, logical bottom and top MUST NOT have changed.
 
10697
         *   - All values above the top are unreachable but are initialized
 
10698
         *     to UNDEFINED_UNUSED, up to the post-realloc valstack_end.
 
10699
         *   - 'old_end_offset' must be computed after realloc to be correct.
 
10700
         */
 
10701
 
 
10702
        DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
 
10703
        DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
 
10704
 
 
10705
        /* success, fixup pointers */
 
10706
        old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack));  /* must be computed after realloc */
 
10707
#ifdef DUK_USE_DEBUG
 
10708
        old_valstack_post = thr->valstack;
 
10709
#endif
 
10710
        thr->valstack = new_valstack;
 
10711
        thr->valstack_end = new_valstack + new_size;
 
10712
        thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
 
10713
        thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_valstack + old_top_offset);
 
10714
 
 
10715
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
10716
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
10717
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
10718
 
 
10719
        /* useful for debugging */
 
10720
#ifdef DUK_USE_DEBUG
 
10721
        if (old_end_offset_pre != old_end_offset_post) {
 
10722
                DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
 
10723
                           "end offset changed: %d -> %d",
 
10724
                           old_end_offset_pre,
 
10725
                           old_end_offset_post);
 
10726
        }
 
10727
        if (old_valstack_pre != old_valstack_post) {
 
10728
                DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
 
10729
                           (void *) old_valstack_pre,
 
10730
                           (void *) old_valstack_post);
 
10731
        }
 
10732
#endif
 
10733
 
 
10734
        DUK_DDPRINT("resized valstack to %d elements (%d bytes), bottom=%d, top=%d, "
 
10735
                    "new pointers: start=%p end=%p bottom=%p top=%p",
 
10736
                    (int) new_size, (int) new_alloc_size,
 
10737
                    (int) (thr->valstack_bottom - thr->valstack),
 
10738
                    (int) (thr->valstack_top - thr->valstack),
 
10739
                    (void *) thr->valstack, (void *) thr->valstack_end,
 
10740
                    (void *) thr->valstack_bottom, (void *) thr->valstack_top);
 
10741
 
 
10742
        /* init newly allocated slots (only) */
 
10743
        p = (duk_tval *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
 
10744
        while (p < thr->valstack_end) {
 
10745
                /* never executed if new size is smaller */
 
10746
                DUK_TVAL_SET_UNDEFINED_UNUSED(p);
 
10747
                p++;
 
10748
        }
 
10749
 
 
10750
        /* assertion check: we try to maintain elements above top in known state */
 
10751
#ifdef DUK_USE_ASSERTIONS
 
10752
        p = thr->valstack_top;
 
10753
        while (p < thr->valstack_end) {
 
10754
                /* everything above old valstack top should be preinitialized now */
 
10755
                DUK_ASSERT(DUK_TVAL_IS_UNDEFINED_UNUSED(p));
 
10756
                p++;
 
10757
        }
 
10758
#endif
 
10759
        return 1;
 
10760
}
 
10761
 
 
10762
static int duk__check_valstack_resize_helper(duk_context *ctx,
 
10763
                                             size_t min_new_size,
 
10764
                                             int shrink_flag,
 
10765
                                             int compact_flag,
 
10766
                                             int throw_flag) {
 
10767
        duk_hthread *thr = (duk_hthread *) ctx;
 
10768
        size_t old_size;
 
10769
        size_t new_size;
 
10770
        int is_shrink = 0;
 
10771
 
 
10772
        DUK_DDDPRINT("check valstack resize: min_new_size=%d, curr_size=%d, curr_top=%d, "
 
10773
                     "curr_bottom=%d, shrink=%d, compact=%d, throw=%d",
 
10774
                     (int) min_new_size,
 
10775
                     (int) (thr->valstack_end - thr->valstack),
 
10776
                     (int) (thr->valstack_top - thr->valstack),
 
10777
                     (int) (thr->valstack_bottom - thr->valstack),
 
10778
                     shrink_flag, compact_flag, throw_flag);
 
10779
 
 
10780
        DUK_ASSERT(ctx != NULL);
 
10781
        DUK_ASSERT(thr != NULL);
 
10782
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
10783
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
10784
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
10785
 
 
10786
        old_size = (size_t) (thr->valstack_end - thr->valstack);
 
10787
 
 
10788
        if (min_new_size <= old_size) {
 
10789
                is_shrink = 1;
 
10790
                if (!shrink_flag ||
 
10791
                    old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
 
10792
                        DUK_DDDPRINT("no need to grow or shrink valstack");
 
10793
                        return 1;
 
10794
                }
 
10795
        }
 
10796
 
 
10797
        new_size = min_new_size;
 
10798
        if (!compact_flag) {
 
10799
                if (is_shrink) {
 
10800
                        /* shrink case; leave some spare */
 
10801
                        new_size += DUK_VALSTACK_SHRINK_SPARE;
 
10802
                }
 
10803
 
 
10804
                /* round up roughly to next 'grow step' */
 
10805
                new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
 
10806
        }
 
10807
 
 
10808
        DUK_DDPRINT("want to %s valstack: %d -> %d elements (min_new_size %d)",
 
10809
                    (new_size > old_size ? "grow" : "shrink"),
 
10810
                    old_size, new_size, min_new_size);
 
10811
 
 
10812
        if (new_size >= thr->valstack_max) {
 
10813
                /* Note: may be triggered even if minimal new_size would not reach the limit,
 
10814
                 * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account.
 
10815
                 */
 
10816
                if (throw_flag) {
 
10817
                        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "valstack limit");
 
10818
                } else {
 
10819
                        return 0;
 
10820
                }
 
10821
        }
 
10822
 
 
10823
        /*
 
10824
         *  When resizing the valstack, a mark-and-sweep may be triggered for
 
10825
         *  the allocation of the new valstack.  If the mark-and-sweep needs
 
10826
         *  to use our thread for something, it may cause *the same valstack*
 
10827
         *  to be resized recursively.  This happens e.g. when mark-and-sweep
 
10828
         *  finalizers are called.
 
10829
         *
 
10830
         *  This is taken into account carefully in duk__resize_valstack().
 
10831
         */
 
10832
 
 
10833
        if (!duk__resize_valstack(ctx, new_size)) {
 
10834
                if (is_shrink) {
 
10835
                        DUK_DDPRINT("valstack resize failed, but is a shrink, ignore");
 
10836
                        return 1;
 
10837
                }
 
10838
 
 
10839
                DUK_DDPRINT("valstack resize failed");
 
10840
 
 
10841
                if (throw_flag) {
 
10842
                        DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to extend valstack");
 
10843
                } else {
 
10844
                        return 0;
 
10845
                }
 
10846
        }
 
10847
 
 
10848
        DUK_DDDPRINT("valstack resize successful");
 
10849
        return 1;
 
10850
}
 
10851
 
 
10852
#if 0  /* XXX: unused */
 
10853
int duk_check_valstack_resize(duk_context *ctx, unsigned int min_new_size, int allow_shrink) {
 
10854
        return duk__check_valstack_resize_helper(ctx,
 
10855
                                                 min_new_size,  /* min_new_size */
 
10856
                                                 allow_shrink,  /* shrink_flag */
 
10857
                                                 0,             /* compact flag */
 
10858
                                                 0);            /* throw flag */
 
10859
}
 
10860
#endif
 
10861
 
 
10862
void duk_require_valstack_resize(duk_context *ctx, unsigned int min_new_size, int allow_shrink) {
 
10863
        (void) duk__check_valstack_resize_helper(ctx,
 
10864
                                                 min_new_size,  /* min_new_size */
 
10865
                                                 allow_shrink,  /* shrink_flag */
 
10866
                                                 0,             /* compact flag */
 
10867
                                                 1);            /* throw flag */
 
10868
}
 
10869
 
 
10870
int duk_check_stack(duk_context *ctx, unsigned int extra) {
 
10871
        duk_hthread *thr = (duk_hthread *) ctx;
 
10872
        unsigned int min_new_size;
 
10873
 
 
10874
        DUK_ASSERT(ctx != NULL);
 
10875
        DUK_ASSERT(thr != NULL);
 
10876
 
 
10877
        min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
 
10878
        return duk__check_valstack_resize_helper(ctx,
 
10879
                                                 min_new_size,  /* min_new_size */
 
10880
                                                 0,             /* shrink_flag */
 
10881
                                                 0,             /* compact flag */
 
10882
                                                 0);            /* throw flag */
 
10883
}
 
10884
 
 
10885
void duk_require_stack(duk_context *ctx, unsigned int extra) {
 
10886
        duk_hthread *thr = (duk_hthread *) ctx;
 
10887
        unsigned int min_new_size;
 
10888
 
 
10889
        DUK_ASSERT(ctx != NULL);
 
10890
        DUK_ASSERT(thr != NULL);
 
10891
 
 
10892
        min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
 
10893
        (void) duk__check_valstack_resize_helper(ctx,
 
10894
                                                 min_new_size,  /* min_new_size */
 
10895
                                                 0,             /* shrink_flag */
 
10896
                                                 0,             /* compact flag */
 
10897
                                                 1);            /* throw flag */
 
10898
}
 
10899
 
 
10900
int duk_check_stack_top(duk_context *ctx, unsigned int top) {
 
10901
        unsigned int min_new_size;
 
10902
 
 
10903
        DUK_ASSERT(ctx != NULL);
 
10904
 
 
10905
        min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
 
10906
        return duk__check_valstack_resize_helper(ctx,
 
10907
                                                 min_new_size,  /* min_new_size */
 
10908
                                                 0,             /* shrink_flag */
 
10909
                                                 0,             /* compact flag */
 
10910
                                                 0);            /* throw flag */
 
10911
}
 
10912
 
 
10913
void duk_require_stack_top(duk_context *ctx, unsigned int top) {
 
10914
        unsigned int min_new_size;
 
10915
 
 
10916
        DUK_ASSERT(ctx != NULL);
 
10917
 
 
10918
        min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
 
10919
        (void) duk__check_valstack_resize_helper(ctx,
 
10920
                                                 min_new_size,  /* min_new_size */
 
10921
                                                 0,             /* shrink_flag */
 
10922
                                                 0,             /* compact flag */
 
10923
                                                 1);            /* throw flag */
 
10924
}
 
10925
 
 
10926
/*
 
10927
 *  Stack manipulation
 
10928
 */
 
10929
 
 
10930
void duk_swap(duk_context *ctx, int index1, int index2) {
 
10931
        duk_tval *tv1;
 
10932
        duk_tval *tv2;
 
10933
        duk_tval tv;  /* temp */
 
10934
 
 
10935
        DUK_ASSERT(ctx != NULL);
 
10936
 
 
10937
        tv1 = duk_require_tval(ctx, index1);
 
10938
        DUK_ASSERT(tv1 != NULL);
 
10939
        tv2 = duk_require_tval(ctx, index2);
 
10940
        DUK_ASSERT(tv2 != NULL);
 
10941
 
 
10942
        DUK_TVAL_SET_TVAL(&tv, tv1);
 
10943
        DUK_TVAL_SET_TVAL(tv1, tv2);
 
10944
        DUK_TVAL_SET_TVAL(tv2, &tv);    
 
10945
}
 
10946
 
 
10947
void duk_swap_top(duk_context *ctx, int index) {
 
10948
        DUK_ASSERT(ctx != NULL);
 
10949
 
 
10950
        duk_swap(ctx, index, -1);
 
10951
}
 
10952
 
 
10953
void duk_dup(duk_context *ctx, int from_index) {
 
10954
        duk_tval *tv;
 
10955
 
 
10956
        DUK_ASSERT(ctx != NULL);
 
10957
 
 
10958
        tv = duk_require_tval(ctx, from_index);
 
10959
        DUK_ASSERT(tv != NULL);
 
10960
 
 
10961
        duk_push_tval(ctx, tv);
 
10962
}
 
10963
 
 
10964
void duk_dup_top(duk_context *ctx) {
 
10965
        DUK_ASSERT(ctx != NULL);
 
10966
 
 
10967
        duk_dup(ctx, -1);
 
10968
}
 
10969
 
 
10970
void duk_insert(duk_context *ctx, int to_index) {
 
10971
        duk_tval *p;
 
10972
        duk_tval *q;
 
10973
        duk_tval tv;
 
10974
        size_t nbytes;
 
10975
 
 
10976
        DUK_ASSERT(ctx != NULL);
 
10977
 
 
10978
        p = duk_require_tval(ctx, to_index);
 
10979
        DUK_ASSERT(p != NULL);
 
10980
        q = duk_require_tval(ctx, -1);
 
10981
        DUK_ASSERT(q != NULL);
 
10982
 
 
10983
        DUK_ASSERT(q >= p);
 
10984
 
 
10985
        /*              nbytes
 
10986
         *           <--------->
 
10987
         *    [ ... | p | x | x | q ]
 
10988
         * => [ ... | q | p | x | x ]
 
10989
         */
 
10990
 
 
10991
        nbytes = (size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));  /* Note: 'q' is top-1 */
 
10992
 
 
10993
        DUK_DDDPRINT("duk_insert: to_index=%p, p=%p, q=%p, nbytes=%d", to_index, p, q, nbytes);
 
10994
        if (nbytes > 0) {
 
10995
                DUK_TVAL_SET_TVAL(&tv, q);
 
10996
                DUK_MEMMOVE((void *) (p + 1), (void *) p, nbytes);
 
10997
                DUK_TVAL_SET_TVAL(p, &tv);
 
10998
        } else {
 
10999
                /* nop: insert top to top */
 
11000
                DUK_ASSERT(nbytes == 0);
 
11001
                DUK_ASSERT(p == q);
 
11002
        }
 
11003
}
 
11004
 
 
11005
void duk_replace(duk_context *ctx, int to_index) {
 
11006
        duk_hthread *thr = (duk_hthread *) ctx;
 
11007
        duk_tval *tv1;
 
11008
        duk_tval *tv2;
 
11009
        duk_tval tv;  /* temp */
 
11010
 
 
11011
        DUK_ASSERT(ctx != NULL);
 
11012
 
 
11013
        tv1 = duk_require_tval(ctx, -1);
 
11014
        DUK_ASSERT(tv1 != NULL);
 
11015
        tv2 = duk_require_tval(ctx, to_index);
 
11016
        DUK_ASSERT(tv2 != NULL);
 
11017
 
 
11018
        /* For tv1 == tv2, both pointing to stack top, the end result
 
11019
         * is same as duk_pop(ctx).
 
11020
         */
 
11021
 
 
11022
        DUK_TVAL_SET_TVAL(&tv, tv2);
 
11023
        DUK_TVAL_SET_TVAL(tv2, tv1);
 
11024
        DUK_TVAL_SET_UNDEFINED_UNUSED(tv1);
 
11025
        thr->valstack_top--;
 
11026
        DUK_TVAL_DECREF(thr, &tv);
 
11027
}
 
11028
 
 
11029
void duk_remove(duk_context *ctx, int index) {
 
11030
        duk_hthread *thr = (duk_hthread *) ctx;
 
11031
        duk_tval *p;
 
11032
        duk_tval *q;
 
11033
#ifdef DUK_USE_REFERENCE_COUNTING
 
11034
        duk_tval tv;
 
11035
#endif
 
11036
        size_t nbytes;
 
11037
 
 
11038
        DUK_ASSERT(ctx != NULL);
 
11039
 
 
11040
        p = duk_require_tval(ctx, index);
 
11041
        DUK_ASSERT(p != NULL);
 
11042
        q = duk_require_tval(ctx, -1);
 
11043
        DUK_ASSERT(q != NULL);
 
11044
 
 
11045
        DUK_ASSERT(q >= p);
 
11046
 
 
11047
        /*              nbytes
 
11048
         *           <--------->
 
11049
         *    [ ... | p | x | x | q ]
 
11050
         * => [ ... | x | x | q ]
 
11051
         */
 
11052
 
 
11053
#ifdef DUK_USE_REFERENCE_COUNTING
 
11054
        /* use a temp: decref only when valstack reachable values are correct */
 
11055
        DUK_TVAL_SET_TVAL(&tv, p);
 
11056
#endif
 
11057
 
 
11058
        nbytes = (size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));  /* Note: 'q' is top-1 */
 
11059
        if (nbytes > 0) {
 
11060
                DUK_MEMMOVE(p, p + 1, nbytes);
 
11061
        }
 
11062
        DUK_TVAL_SET_UNDEFINED_UNUSED(q);
 
11063
        thr->valstack_top--;
 
11064
 
 
11065
#ifdef DUK_USE_REFERENCE_COUNTING
 
11066
        DUK_TVAL_DECREF(thr, &tv);
 
11067
#endif
 
11068
}
 
11069
 
 
11070
void duk_xmove(duk_context *ctx, duk_context *from_ctx, unsigned int count) {
 
11071
        duk_hthread *thr = (duk_hthread *) ctx;
 
11072
        duk_hthread *from_thr = (duk_hthread *) from_ctx;
 
11073
        void *src;
 
11074
        duk_size_t nbytes;
 
11075
        duk_tval *p;
 
11076
 
 
11077
        DUK_ASSERT(ctx != NULL);
 
11078
        DUK_ASSERT(from_ctx != NULL);
 
11079
 
 
11080
        nbytes = sizeof(duk_tval) * count;
 
11081
        if (nbytes == 0) {
 
11082
                return;
 
11083
        }
 
11084
        DUK_ASSERT(thr->valstack_top <= thr->valstack_end);
 
11085
        if ((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack_top) < nbytes) {
 
11086
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
11087
        }
 
11088
        src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
 
11089
        if (src < (void *) thr->valstack_bottom) {
 
11090
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "source stack does not contain enough elements");
 
11091
        }
 
11092
 
 
11093
        /* copy values (no overlap even if ctx == from_ctx) */
 
11094
        DUK_MEMCPY((void *) thr->valstack_top, src, nbytes);
 
11095
 
 
11096
        /* incref them */
 
11097
        p = thr->valstack_top;
 
11098
        thr->valstack_top = (duk_tval *) (((duk_uint8_t *) thr->valstack_top) + nbytes);
 
11099
        while (p < thr->valstack_top) {
 
11100
                DUK_TVAL_INCREF(thr, p);
 
11101
                p++;
 
11102
        }
 
11103
}
 
11104
 
 
11105
/*
 
11106
 *  Get/require
 
11107
 */
 
11108
 
 
11109
/* internal */
 
11110
duk_tval *duk_get_tval(duk_context *ctx, int index) {
 
11111
        duk_hthread *thr = (duk_hthread *) ctx;
 
11112
        duk_tval *tv;
 
11113
 
 
11114
        DUK_ASSERT(ctx != NULL);
 
11115
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
11116
 
 
11117
        if (index < 0) {
 
11118
                if (index == DUK_INVALID_INDEX) {
 
11119
                        return NULL;
 
11120
                }
 
11121
                tv = thr->valstack_top + index;
 
11122
                DUK_ASSERT(tv < thr->valstack_top);
 
11123
                if (tv < thr->valstack_bottom) {
 
11124
                        return NULL;
 
11125
                }
 
11126
        } else {
 
11127
                tv = thr->valstack_bottom + index;
 
11128
                DUK_ASSERT(tv >= thr->valstack_bottom);
 
11129
                if (tv >= thr->valstack_top) {
 
11130
                        return NULL;
 
11131
                }
 
11132
        }
 
11133
        return tv;
 
11134
}
 
11135
 
 
11136
duk_tval *duk_require_tval(duk_context *ctx, int index) {
 
11137
        duk_hthread *thr = (duk_hthread *) ctx;
 
11138
        duk_tval *tv;
 
11139
 
 
11140
        DUK_ASSERT(ctx != NULL);
 
11141
        DUK_ASSERT(DUK_INVALID_INDEX < 0);
 
11142
 
 
11143
        if (index < 0) {
 
11144
                if (index == DUK_INVALID_INDEX) {
 
11145
                        /* XXX: this check may not be necessary
 
11146
                         * on some architectures but be careful
 
11147
                         * of wrapping.
 
11148
                         */
 
11149
                        goto fail;
 
11150
                }
 
11151
                tv = thr->valstack_top + index;
 
11152
                DUK_ASSERT(tv < thr->valstack_top);
 
11153
                if (DUK_UNLIKELY(tv < thr->valstack_bottom)) {
 
11154
                        goto fail;
 
11155
                }
 
11156
        } else {
 
11157
                tv = thr->valstack_bottom + index;
 
11158
                DUK_ASSERT(tv >= thr->valstack_bottom);
 
11159
                if (DUK_UNLIKELY(tv >= thr->valstack_top)) {
 
11160
                        goto fail;
 
11161
                }
 
11162
        }
 
11163
        return tv;
 
11164
 
 
11165
 fail:
 
11166
        DUK_ERROR(thr, DUK_ERR_API_ERROR, "index out of bounds");
 
11167
        return NULL;  /* not reachable */
 
11168
}
 
11169
 
 
11170
void duk_require_undefined(duk_context *ctx, int index) {
 
11171
        duk_hthread *thr = (duk_hthread *) ctx;
 
11172
        duk_tval *tv;
 
11173
 
 
11174
        DUK_ASSERT(ctx != NULL);
 
11175
 
 
11176
        tv = duk_get_tval(ctx, index);
 
11177
        if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
 
11178
                /* Note: accept both 'actual' and 'unused' undefined */
 
11179
                return;
 
11180
        }
 
11181
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not undefined");
 
11182
}
 
11183
 
 
11184
void duk_require_null(duk_context *ctx, int index) {
 
11185
        duk_hthread *thr = (duk_hthread *) ctx;
 
11186
        duk_tval *tv;
 
11187
 
 
11188
        DUK_ASSERT(ctx != NULL);
 
11189
 
 
11190
        tv = duk_get_tval(ctx, index);
 
11191
        if (tv && DUK_TVAL_IS_NULL(tv)) {
 
11192
                return;
 
11193
        }
 
11194
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not null");
 
11195
}
 
11196
 
 
11197
int duk_get_boolean(duk_context *ctx, int index) {
 
11198
        int ret = 0;  /* default: false */
 
11199
        duk_tval *tv;
 
11200
 
 
11201
        DUK_ASSERT(ctx != NULL);
 
11202
 
 
11203
        tv = duk_get_tval(ctx, index);
 
11204
        if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
 
11205
                ret = DUK_TVAL_GET_BOOLEAN(tv);
 
11206
        }
 
11207
 
 
11208
        DUK_ASSERT(ret == 0 || ret == 1);
 
11209
        return ret;
 
11210
}
 
11211
 
 
11212
int duk_require_boolean(duk_context *ctx, int index) {
 
11213
        duk_hthread *thr = (duk_hthread *) ctx;
 
11214
        duk_tval *tv;
 
11215
 
 
11216
        DUK_ASSERT(ctx != NULL);
 
11217
 
 
11218
        tv = duk_get_tval(ctx, index);
 
11219
        if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
 
11220
                int ret = DUK_TVAL_GET_BOOLEAN(tv);
 
11221
                DUK_ASSERT(ret == 0 || ret == 1);
 
11222
                return ret;
 
11223
        }
 
11224
 
 
11225
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not boolean");
 
11226
        return 0;  /* not reachable */
 
11227
}
 
11228
 
 
11229
double duk_get_number(duk_context *ctx, int index) {
 
11230
        duk_double_union ret;
 
11231
        duk_tval *tv;
 
11232
 
 
11233
        DUK_ASSERT(ctx != NULL);
 
11234
 
 
11235
        ret.d = DUK_DOUBLE_NAN;  /* default: NaN */
 
11236
        tv = duk_get_tval(ctx, index);
 
11237
        if (tv && DUK_TVAL_IS_NUMBER(tv)) {
 
11238
                ret.d = DUK_TVAL_GET_NUMBER(tv);
 
11239
        }
 
11240
 
 
11241
        /*
 
11242
         *  Number should already be in NaN-normalized form,
 
11243
         *  but let's normalize anyway.
 
11244
         */
 
11245
 
 
11246
        DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
 
11247
        return ret.d;
 
11248
}
 
11249
 
 
11250
double duk_require_number(duk_context *ctx, int index) {
 
11251
        duk_hthread *thr = (duk_hthread *) ctx;
 
11252
        duk_tval *tv;
 
11253
 
 
11254
        DUK_ASSERT(ctx != NULL);
 
11255
 
 
11256
        tv = duk_get_tval(ctx, index);
 
11257
        if (tv && DUK_TVAL_IS_NUMBER(tv)) {
 
11258
                duk_double_union ret;
 
11259
                ret.d = DUK_TVAL_GET_NUMBER(tv);
 
11260
 
 
11261
                /*
 
11262
                 *  Number should already be in NaN-normalized form,
 
11263
                 *  but let's normalize anyway.
 
11264
                 */
 
11265
 
 
11266
                DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
 
11267
                return ret.d;
 
11268
        }
 
11269
 
 
11270
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not number");
 
11271
        return DUK_DOUBLE_NAN;  /* not reachable */
 
11272
}
 
11273
 
 
11274
int duk_get_int(duk_context *ctx, int index) {
 
11275
        /* Custom coercion for API */
 
11276
        return duk__api_coerce_d2i(duk_get_number(ctx, index));
 
11277
}
 
11278
 
 
11279
int duk_require_int(duk_context *ctx, int index) {
 
11280
        /* Custom coercion for API */
 
11281
        return duk__api_coerce_d2i(duk_require_number(ctx, index));
 
11282
}
 
11283
 
 
11284
const char *duk_get_lstring(duk_context *ctx, int index, size_t *out_len) {
 
11285
        const char *ret;
 
11286
        duk_tval *tv;
 
11287
 
 
11288
        DUK_ASSERT(ctx != NULL);
 
11289
 
 
11290
        /* default: NULL, length 0 */
 
11291
        ret = NULL;
 
11292
        if (out_len) {
 
11293
                *out_len = 0;
 
11294
        }
 
11295
 
 
11296
        tv = duk_get_tval(ctx, index);
 
11297
        if (tv && DUK_TVAL_IS_STRING(tv)) {
 
11298
                /* Here we rely on duk_hstring instances always being zero
 
11299
                 * terminated even if the actual string is not.
 
11300
                 */
 
11301
                duk_hstring *h = DUK_TVAL_GET_STRING(tv);
 
11302
                DUK_ASSERT(h != NULL);
 
11303
                ret = (const char *) DUK_HSTRING_GET_DATA(h);
 
11304
                if (out_len) {
 
11305
                        *out_len = DUK_HSTRING_GET_BYTELEN(h);
 
11306
                }
 
11307
        }
 
11308
 
 
11309
        return ret;
 
11310
}
 
11311
 
 
11312
const char *duk_require_lstring(duk_context *ctx, int index, size_t *out_len) {
 
11313
        duk_hthread *thr = (duk_hthread *) ctx;
 
11314
        const char *ret;
 
11315
 
 
11316
        DUK_ASSERT(ctx != NULL);
 
11317
 
 
11318
        /* Note: this check relies on the fact that even a zero-size string
 
11319
         * has a non-NULL pointer.
 
11320
         */
 
11321
        ret = duk_get_lstring(ctx, index, out_len);
 
11322
        if (ret) {
 
11323
                return ret;
 
11324
        }
 
11325
 
 
11326
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not string");
 
11327
        return NULL;  /* not reachable */
 
11328
}
 
11329
 
 
11330
const char *duk_get_string(duk_context *ctx, int index) {
 
11331
        DUK_ASSERT(ctx != NULL);
 
11332
 
 
11333
        return duk_get_lstring(ctx, index, NULL);
 
11334
}
 
11335
 
 
11336
const char *duk_require_string(duk_context *ctx, int index) {
 
11337
        DUK_ASSERT(ctx != NULL);
 
11338
 
 
11339
        return duk_require_lstring(ctx, index, NULL);
 
11340
}
 
11341
 
 
11342
void *duk_get_pointer(duk_context *ctx, int index) {
 
11343
        duk_tval *tv;
 
11344
 
 
11345
        DUK_ASSERT(ctx != NULL);
 
11346
 
 
11347
        tv = duk_get_tval(ctx, index);
 
11348
        if (tv && DUK_TVAL_IS_POINTER(tv)) {
 
11349
                void *p = DUK_TVAL_GET_POINTER(tv);  /* may be NULL */
 
11350
                return (void *) p;
 
11351
        }
 
11352
 
 
11353
        return NULL;
 
11354
}
 
11355
 
 
11356
void *duk_require_pointer(duk_context *ctx, int index) {
 
11357
        duk_hthread *thr = (duk_hthread *) ctx;
 
11358
        duk_tval *tv;
 
11359
 
 
11360
        DUK_ASSERT(ctx != NULL);
 
11361
 
 
11362
        /* Note: here we must be wary of the fact that a pointer may be
 
11363
         * valid and be a NULL.
 
11364
         */
 
11365
        tv = duk_get_tval(ctx, index);
 
11366
        if (tv && DUK_TVAL_IS_POINTER(tv)) {
 
11367
                void *p = DUK_TVAL_GET_POINTER(tv);  /* may be NULL */
 
11368
                return (void *) p;
 
11369
        }
 
11370
 
 
11371
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not pointer");
 
11372
        return NULL;  /* not reachable */
 
11373
}
 
11374
 
 
11375
void *duk_get_voidptr(duk_context *ctx, int index) {
 
11376
        duk_tval *tv;
 
11377
 
 
11378
        DUK_ASSERT(ctx != NULL);
 
11379
 
 
11380
        tv = duk_get_tval(ctx, index);
 
11381
        if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
 
11382
                duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
 
11383
                DUK_ASSERT(h != NULL);
 
11384
                return (void *) h;
 
11385
        }
 
11386
 
 
11387
        return NULL;
 
11388
}
 
11389
 
 
11390
void *duk_get_buffer(duk_context *ctx, int index, size_t *out_size) {
 
11391
        duk_tval *tv;
 
11392
 
 
11393
        DUK_ASSERT(ctx != NULL);
 
11394
 
 
11395
        if (out_size != NULL) {
 
11396
                *out_size = 0;
 
11397
        }
 
11398
 
 
11399
        tv = duk_get_tval(ctx, index);
 
11400
        if (tv && DUK_TVAL_IS_BUFFER(tv)) {
 
11401
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
11402
                DUK_ASSERT(h != NULL);
 
11403
                if (out_size) {
 
11404
                        *out_size = DUK_HBUFFER_GET_SIZE(h);
 
11405
                }
 
11406
                return (void *) DUK_HBUFFER_GET_DATA_PTR(h);  /* may be NULL (but only if size is 0) */
 
11407
        }
 
11408
 
 
11409
        return NULL;
 
11410
}
 
11411
 
 
11412
void *duk_require_buffer(duk_context *ctx, int index, size_t *out_size) {
 
11413
        duk_hthread *thr = (duk_hthread *) ctx;
 
11414
        duk_tval *tv;
 
11415
 
 
11416
        DUK_ASSERT(ctx != NULL);
 
11417
 
 
11418
        if (out_size != NULL) {
 
11419
                *out_size = 0;
 
11420
        }
 
11421
 
 
11422
        /* Note: here we must be wary of the fact that a data pointer may
 
11423
         * be a NULL for a zero-size buffer.
 
11424
         */
 
11425
        
 
11426
        tv = duk_get_tval(ctx, index);
 
11427
        if (tv && DUK_TVAL_IS_BUFFER(tv)) {
 
11428
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
11429
                DUK_ASSERT(h != NULL);
 
11430
                if (out_size) {
 
11431
                        *out_size = DUK_HBUFFER_GET_SIZE(h);
 
11432
                }
 
11433
                return (void *) DUK_HBUFFER_GET_DATA_PTR(h);  /* may be NULL (but only if size is 0) */
 
11434
        }
 
11435
 
 
11436
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not buffer");
 
11437
        return NULL;  /* not reachable */
 
11438
}
 
11439
 
 
11440
/* Raw helper for getting a value from the stack, checking its tag, and possible its object class. */
 
11441
duk_heaphdr *duk_get_tagged_heaphdr_raw(duk_context *ctx, int index, duk_int_t flags_and_tag) {
 
11442
        duk_hthread *thr = (duk_hthread *) ctx;
 
11443
        duk_tval *tv;
 
11444
        duk_int_t tag = flags_and_tag & 0xffff;  /* tags can be up to 16 bits */
 
11445
 
 
11446
        DUK_ASSERT(ctx != NULL);
 
11447
 
 
11448
        tv = duk_get_tval(ctx, index);
 
11449
        if (tv && DUK_TVAL_GET_TAG(tv) == tag) {
 
11450
                duk_heaphdr *ret;
 
11451
 
 
11452
                /* Note: tag comparison in general doesn't work for numbers,
 
11453
                 * but it does work for everything else (heap objects here).
 
11454
                 */
 
11455
                ret = DUK_TVAL_GET_HEAPHDR(tv);
 
11456
                DUK_ASSERT(ret != NULL);  /* tagged null pointers should never occur */
 
11457
 
 
11458
                /* If class check has been requested, tag must also be DUK_TAG_OBJECT.
 
11459
                 * This allows us to just check the class check flag without checking
 
11460
                 * the tag also.
 
11461
                 */
 
11462
                DUK_ASSERT((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 ||
 
11463
                           tag == DUK_TAG_OBJECT);
 
11464
 
 
11465
                if ((flags_and_tag & DUK_GETTAGGED_FLAG_CHECK_CLASS) == 0 ||  /* no class check */
 
11466
                    (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) ret) ==  /* or class check matches */
 
11467
                        (duk_int_t) ((flags_and_tag >> DUK_GETTAGGED_CLASS_SHIFT) & 0xff)) {
 
11468
                        return ret;
 
11469
                }
 
11470
        }
 
11471
 
 
11472
        if (flags_and_tag & DUK_GETTAGGED_FLAG_ALLOW_NULL) {
 
11473
                return (duk_heaphdr *) NULL;
 
11474
        }
 
11475
 
 
11476
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "incorrect type, expected tag %d", tag);
 
11477
        return NULL;  /* not reachable */
 
11478
}
 
11479
 
 
11480
/* internal */
 
11481
duk_hstring *duk_get_hstring(duk_context *ctx, int index) {
 
11482
        return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11483
}
 
11484
 
 
11485
/* internal */
 
11486
duk_hstring *duk_require_hstring(duk_context *ctx, int index) {
 
11487
        return (duk_hstring *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
 
11488
}
 
11489
 
 
11490
/* internal */
 
11491
duk_hobject *duk_get_hobject(duk_context *ctx, int index) {
 
11492
        return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11493
}
 
11494
 
 
11495
/* internal */
 
11496
duk_hobject *duk_require_hobject(duk_context *ctx, int index) {
 
11497
        return (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
 
11498
}
 
11499
 
 
11500
/* internal */
 
11501
duk_hbuffer *duk_get_hbuffer(duk_context *ctx, int index) {
 
11502
        return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11503
}
 
11504
 
 
11505
/* internal */
 
11506
duk_hbuffer *duk_require_hbuffer(duk_context *ctx, int index) {
 
11507
        return (duk_hbuffer *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
 
11508
}
 
11509
 
 
11510
/* internal */
 
11511
duk_hthread *duk_get_hthread(duk_context *ctx, int index) {
 
11512
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11513
        if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
 
11514
                h = NULL;
 
11515
        }
 
11516
        return (duk_hthread *) h;
 
11517
}
 
11518
 
 
11519
/* internal */
 
11520
duk_hthread *duk_require_hthread(duk_context *ctx, int index) {
 
11521
        duk_hthread *thr = (duk_hthread *) ctx;
 
11522
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
 
11523
        DUK_ASSERT(h != NULL);
 
11524
        if (!DUK_HOBJECT_IS_THREAD(h)) {
 
11525
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "incorrect type, expected thread");
 
11526
        }
 
11527
        return (duk_hthread *) h;
 
11528
}
 
11529
 
 
11530
/* internal */
 
11531
duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, int index) {
 
11532
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11533
        if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
11534
                h = NULL;
 
11535
        }
 
11536
        return (duk_hcompiledfunction *) h;
 
11537
}
 
11538
 
 
11539
/* internal */
 
11540
duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, int index) {
 
11541
        duk_hthread *thr = (duk_hthread *) ctx;
 
11542
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
 
11543
        DUK_ASSERT(h != NULL);
 
11544
        if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
11545
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "incorrect type, expected compiledfunction");
 
11546
        }
 
11547
        return (duk_hcompiledfunction *) h;
 
11548
}
 
11549
 
 
11550
/* internal */
 
11551
duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, int index) {
 
11552
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT | DUK_GETTAGGED_FLAG_ALLOW_NULL);
 
11553
        if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
11554
                h = NULL;
 
11555
        }
 
11556
        return (duk_hnativefunction *) h;
 
11557
}
 
11558
 
 
11559
/* internal */
 
11560
duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, int index) {
 
11561
        duk_hthread *thr = (duk_hthread *) ctx;
 
11562
        duk_hobject *h = (duk_hobject *) duk_get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
 
11563
        DUK_ASSERT(h != NULL);
 
11564
        if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
11565
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "incorrect type, expected nativefunction");
 
11566
        }
 
11567
        return (duk_hnativefunction *) h;
 
11568
}
 
11569
 
 
11570
#if 0  /* FIXME: unused */
 
11571
/* about 300 bytes, worth it? */
 
11572
void duk_get_multiple(duk_context *ctx, int start_index, const char *types, ...) {
 
11573
        va_list ap;
 
11574
        duk_hthread *thr;
 
11575
        const char *p;
 
11576
        int index;
 
11577
 
 
11578
        DUK_ASSERT(ctx != NULL);
 
11579
        DUK_ASSERT(types != NULL);
 
11580
 
 
11581
        thr = (duk_hthread *) ctx;
 
11582
        index = duk_require_normalize_index(ctx, start_index);
 
11583
 
 
11584
        va_start(ap, types);
 
11585
 
 
11586
        p = types;
 
11587
        for (;;) {
 
11588
                unsigned int ch = (unsigned int) (*p++);
 
11589
                switch (ch) {
 
11590
                case 'u': {
 
11591
                        /* no effect */
 
11592
                        break;
 
11593
                }
 
11594
                case 'n': {
 
11595
                        /* no effect */
 
11596
                        break;
 
11597
                }
 
11598
                case 'b': {
 
11599
                        int *out = va_arg(ap, int *);
 
11600
                        DUK_ASSERT(out);
 
11601
                        *out = duk_get_boolean(ctx, index);
 
11602
                        break;
 
11603
                }
 
11604
                case 'd': {
 
11605
                        double *out = va_arg(ap, double *);
 
11606
                        DUK_ASSERT(out);
 
11607
                        *out = duk_get_number(ctx, index);
 
11608
                        break;
 
11609
                }
 
11610
                case 'i': {
 
11611
                        int *out = va_arg(ap, int *);
 
11612
                        DUK_ASSERT(out);
 
11613
                        *out = duk_get_int(ctx, index);
 
11614
                        break;
 
11615
                }
 
11616
                case 's': {
 
11617
                        const char **out = va_arg(ap, const char **);
 
11618
                        DUK_ASSERT(out);
 
11619
                        *out = duk_get_string(ctx, index);
 
11620
                        break;
 
11621
                }
 
11622
                case 'l': {
 
11623
                        const char **out1 = va_arg(ap, const char **);
 
11624
                        size_t *out2 = va_arg(ap, size_t *);
 
11625
                        DUK_ASSERT(out1);
 
11626
                        DUK_ASSERT(out2);
 
11627
                        *out1 = duk_get_lstring(ctx, index, out2);
 
11628
                        break;
 
11629
                }
 
11630
                case 'p': {
 
11631
                        void **out = va_arg(ap, void **);
 
11632
                        DUK_ASSERT(out);
 
11633
                        *out = duk_get_pointer(ctx, index);
 
11634
                        break;
 
11635
                }
 
11636
                case '-': {
 
11637
                        break;
 
11638
                }
 
11639
                case 0: {
 
11640
                        goto done;
 
11641
                }
 
11642
                default: {
 
11643
                        DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid type char: %d", ch);
 
11644
                }
 
11645
                }
 
11646
 
 
11647
                index++;
 
11648
        }
 
11649
 done:
 
11650
 
 
11651
        va_end(ap);
 
11652
}
 
11653
#endif  /* FIXME: unused */
 
11654
 
 
11655
duk_c_function duk_get_c_function(duk_context *ctx, int index) {
 
11656
        duk_tval *tv;
 
11657
        duk_hobject *h;
 
11658
        duk_hnativefunction *f;
 
11659
 
 
11660
        DUK_ASSERT(ctx != NULL);
 
11661
 
 
11662
        tv = duk_get_tval(ctx, index);
 
11663
        if (!tv) {
 
11664
                return NULL;
 
11665
        }
 
11666
        if (!DUK_TVAL_IS_OBJECT(tv)) {
 
11667
                return NULL;
 
11668
        }
 
11669
        h = DUK_TVAL_GET_OBJECT(tv);
 
11670
        DUK_ASSERT(h != NULL);
 
11671
        
 
11672
        if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
11673
                return NULL;
 
11674
        }
 
11675
        DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
 
11676
        f = (duk_hnativefunction *) h;
 
11677
 
 
11678
        return f->func;
 
11679
}
 
11680
 
 
11681
duk_c_function duk_require_c_function(duk_context *ctx, int index) {
 
11682
        duk_hthread *thr = (duk_hthread *) ctx;
 
11683
        duk_c_function ret;
 
11684
 
 
11685
        ret = duk_get_c_function(ctx, index);
 
11686
        if (!ret) {
 
11687
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "incorrect type, expected c function");
 
11688
        }
 
11689
        return ret;
 
11690
}
 
11691
 
 
11692
duk_context *duk_get_context(duk_context *ctx, int index) {
 
11693
        duk_hobject *h;
 
11694
 
 
11695
        h = duk_get_hobject(ctx, index);
 
11696
        if (!h) {
 
11697
                return NULL;
 
11698
        }
 
11699
        if (!DUK_HOBJECT_HAS_THREAD(h)) {
 
11700
                return NULL;
 
11701
        }
 
11702
        return (duk_context *) h;
 
11703
}
 
11704
 
 
11705
duk_context *duk_require_context(duk_context *ctx, int index) {
 
11706
        return (duk_context *) duk_require_hthread(ctx, index);
 
11707
}
 
11708
 
 
11709
size_t duk_get_length(duk_context *ctx, int index) {
 
11710
        duk_tval *tv;
 
11711
 
 
11712
        DUK_ASSERT(ctx != NULL);
 
11713
 
 
11714
        tv = duk_get_tval(ctx, index);
 
11715
        if (!tv) {
 
11716
                return 0;
 
11717
        }
 
11718
 
 
11719
        switch (DUK_TVAL_GET_TAG(tv)) {
 
11720
        case DUK_TAG_UNDEFINED:
 
11721
        case DUK_TAG_NULL:
 
11722
        case DUK_TAG_BOOLEAN:
 
11723
        case DUK_TAG_POINTER:
 
11724
                return 0;
 
11725
        case DUK_TAG_STRING: {
 
11726
                duk_hstring *h = DUK_TVAL_GET_STRING(tv);
 
11727
                DUK_ASSERT(h != NULL);
 
11728
                return (size_t) DUK_HSTRING_GET_CHARLEN(h);
 
11729
        }
 
11730
        case DUK_TAG_OBJECT: {
 
11731
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
11732
                DUK_ASSERT(h != NULL);
 
11733
                return (size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
 
11734
        }
 
11735
        case DUK_TAG_BUFFER: {
 
11736
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
11737
                DUK_ASSERT(h != NULL);
 
11738
                return (size_t) DUK_HBUFFER_GET_SIZE(h);
 
11739
        }
 
11740
        default:
 
11741
                /* number */
 
11742
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
11743
                return 0;
 
11744
        }
 
11745
 
 
11746
        DUK_UNREACHABLE();
 
11747
}
 
11748
 
 
11749
/*
 
11750
 *  Conversions and coercions
 
11751
 *
 
11752
 *  The conversion/coercions are in-place operations on the value stack.
 
11753
 *  Some operations are implemented here directly, while others call a
 
11754
 *  helper in duk_js_ops.c after validating arguments.
 
11755
 */
 
11756
 
 
11757
/* E5 Section 8.12.8 */
 
11758
 
 
11759
static int duk__defaultvalue_coerce_attempt(duk_context *ctx, int index, int func_stridx) {
 
11760
        if (duk_get_prop_stridx(ctx, index, func_stridx)) {
 
11761
                /* [ ... func ] */
 
11762
                if (duk_is_callable(ctx, -1)) {
 
11763
                        duk_dup(ctx, index);         /* -> [ ... func this ] */
 
11764
                        duk_call_method(ctx, 0);     /* -> [ ... retval ] */
 
11765
                        if (duk_is_primitive(ctx, -1)) {
 
11766
                                duk_replace(ctx, index);
 
11767
                                return 1;
 
11768
                        }
 
11769
                        /* [ ... retval ]; popped below */
 
11770
                }
 
11771
        }
 
11772
        duk_pop(ctx);  /* [ ... func/retval ] -> [ ... ] */
 
11773
        return 0;
 
11774
}
 
11775
 
 
11776
void duk_to_defaultvalue(duk_context *ctx, int index, int hint) {
 
11777
        duk_hthread *thr = (duk_hthread *) ctx;
 
11778
        duk_hobject *obj;
 
11779
        int coercers[] = { DUK_STRIDX_VALUE_OF, DUK_STRIDX_TO_STRING };
 
11780
 
 
11781
        DUK_ASSERT(ctx != NULL);
 
11782
        DUK_ASSERT(thr != NULL);
 
11783
 
 
11784
        index = duk_require_normalize_index(ctx, index);
 
11785
 
 
11786
        if (!duk_is_object(ctx, index)) {
 
11787
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not object");
 
11788
        }
 
11789
        obj = duk_get_hobject(ctx, index);
 
11790
        DUK_ASSERT(obj != NULL);
 
11791
 
 
11792
        if (hint == DUK_HINT_NONE) {
 
11793
                if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
 
11794
                        hint = DUK_HINT_STRING;
 
11795
                } else {
 
11796
                        hint = DUK_HINT_NUMBER;
 
11797
                }
 
11798
        }
 
11799
 
 
11800
        if (hint == DUK_HINT_STRING) {
 
11801
                coercers[0] = DUK_STRIDX_TO_STRING;
 
11802
                coercers[1] = DUK_STRIDX_VALUE_OF;
 
11803
        }
 
11804
 
 
11805
        if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
 
11806
                return;
 
11807
        }
 
11808
 
 
11809
        if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
 
11810
                return;
 
11811
        }
 
11812
 
 
11813
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "failed to coerce with [[DefaultValue]]");
 
11814
}
 
11815
 
 
11816
void duk_to_undefined(duk_context *ctx, int index) {
 
11817
        duk_hthread *thr = (duk_hthread *) ctx;
 
11818
        duk_tval *tv;
 
11819
        duk_tval tv_temp;
 
11820
 
 
11821
        DUK_ASSERT(ctx != NULL);
 
11822
        DUK_UNREF(thr);
 
11823
 
 
11824
        tv = duk_require_tval(ctx, index);
 
11825
        DUK_ASSERT(tv != NULL);
 
11826
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11827
        DUK_TVAL_SET_UNDEFINED_ACTUAL(tv);
 
11828
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11829
}
 
11830
 
 
11831
void duk_to_null(duk_context *ctx, int index) {
 
11832
        duk_hthread *thr = (duk_hthread *) ctx;
 
11833
        duk_tval *tv;
 
11834
        duk_tval tv_temp;
 
11835
 
 
11836
        DUK_ASSERT(ctx != NULL);
 
11837
        DUK_UNREF(thr);
 
11838
 
 
11839
        tv = duk_require_tval(ctx, index);
 
11840
        DUK_ASSERT(tv != NULL);
 
11841
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11842
        DUK_TVAL_SET_NULL(tv);
 
11843
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11844
}
 
11845
 
 
11846
/* E5 Section 9.1 */
 
11847
void duk_to_primitive(duk_context *ctx, int index, int hint) {
 
11848
        duk_tval *tv;
 
11849
 
 
11850
        DUK_ASSERT(ctx != NULL);
 
11851
        DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
 
11852
 
 
11853
        index = duk_require_normalize_index(ctx, index);
 
11854
 
 
11855
        tv = duk_require_tval(ctx, index);
 
11856
        DUK_ASSERT(tv != NULL);
 
11857
 
 
11858
        if (DUK_TVAL_GET_TAG(tv) != DUK_TAG_OBJECT) {
 
11859
                /* everything except object stay as is */
 
11860
                return;
 
11861
        }
 
11862
        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
11863
 
 
11864
        duk_to_defaultvalue(ctx, index, hint);
 
11865
}
 
11866
 
 
11867
/* E5 Section 9.2 */
 
11868
int duk_to_boolean(duk_context *ctx, int index) {
 
11869
        duk_hthread *thr = (duk_hthread *) ctx;
 
11870
        duk_tval *tv;
 
11871
        duk_tval tv_temp;
 
11872
        int val;
 
11873
 
 
11874
        DUK_ASSERT(ctx != NULL);
 
11875
        DUK_UNREF(thr);
 
11876
 
 
11877
        index = duk_require_normalize_index(ctx, index);
 
11878
 
 
11879
        tv = duk_require_tval(ctx, index);
 
11880
        DUK_ASSERT(tv != NULL);
 
11881
 
 
11882
        val = duk_js_toboolean(tv);
 
11883
 
 
11884
        /* Note: no need to re-lookup tv, conversion is side effect free */
 
11885
        DUK_ASSERT(tv != NULL);
 
11886
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11887
        DUK_TVAL_SET_BOOLEAN(tv, val);
 
11888
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11889
        return val;
 
11890
}
 
11891
 
 
11892
double duk_to_number(duk_context *ctx, int index) {
 
11893
        duk_hthread *thr = (duk_hthread *) ctx;
 
11894
        duk_tval *tv;
 
11895
        duk_tval tv_temp;
 
11896
        double d;
 
11897
 
 
11898
        DUK_ASSERT(ctx != NULL);
 
11899
 
 
11900
        tv = duk_require_tval(ctx, index);
 
11901
        DUK_ASSERT(tv != NULL);
 
11902
        d = duk_js_tonumber(thr, tv);
 
11903
 
 
11904
        /* Note: need to re-lookup because ToNumber() may have side effects */
 
11905
        tv = duk_require_tval(ctx, index);
 
11906
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11907
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
11908
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11909
 
 
11910
        return d;
 
11911
}
 
11912
 
 
11913
/* FIXME: combine all the integer conversions: they share everything
 
11914
 * but the helper function for coercion.
 
11915
 */
 
11916
 
 
11917
int duk_to_int(duk_context *ctx, int index) {
 
11918
        duk_hthread *thr = (duk_hthread *) ctx;
 
11919
        duk_tval *tv;
 
11920
        duk_tval tv_temp;
 
11921
        double d;
 
11922
 
 
11923
        DUK_ASSERT(ctx != NULL);
 
11924
 
 
11925
        tv = duk_require_tval(ctx, index);
 
11926
        DUK_ASSERT(tv != NULL);
 
11927
        d = duk_js_tointeger(thr, tv);  /* E5 Section 9.4, ToInteger() */
 
11928
 
 
11929
        /* relookup in case duk_js_tointeger() ends up e.g. coercing an object */
 
11930
        tv = duk_require_tval(ctx, index);
 
11931
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11932
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
11933
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11934
 
 
11935
        /* Custom coercion for API */
 
11936
        return duk__api_coerce_d2i(d);
 
11937
}
 
11938
 
 
11939
int duk_to_int32(duk_context *ctx, int index) {
 
11940
        duk_hthread *thr = (duk_hthread *) ctx;
 
11941
        duk_tval *tv;
 
11942
        duk_tval tv_temp;
 
11943
        double d;
 
11944
 
 
11945
        DUK_ASSERT(ctx != NULL);
 
11946
 
 
11947
        tv = duk_require_tval(ctx, index);
 
11948
        DUK_ASSERT(tv != NULL);
 
11949
        d = (double) duk_js_toint32(thr, tv);
 
11950
 
 
11951
        /* must relookup */
 
11952
        tv = duk_require_tval(ctx, index);
 
11953
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11954
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
11955
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11956
 
 
11957
        /* ToInt32() should already have restricted the result to
 
11958
         * an acceptable range (unless 'int' is less than 32 bits).
 
11959
         */
 
11960
        return (int) d;
 
11961
}
 
11962
 
 
11963
unsigned int duk_to_uint32(duk_context *ctx, int index) {
 
11964
        duk_hthread *thr = (duk_hthread *) ctx;
 
11965
        duk_tval *tv;
 
11966
        duk_tval tv_temp;
 
11967
        double d;
 
11968
 
 
11969
        DUK_ASSERT(ctx != NULL);
 
11970
 
 
11971
        tv = duk_require_tval(ctx, index);
 
11972
        DUK_ASSERT(tv != NULL);
 
11973
        d = (double) duk_js_touint32(thr, tv);
 
11974
 
 
11975
        /* must relookup */
 
11976
        tv = duk_require_tval(ctx, index);
 
11977
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
11978
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
11979
        DUK_TVAL_DECREF(thr, &tv_temp);
 
11980
 
 
11981
        /* ToUint32() should already have restricted the result to
 
11982
         * an acceptable range (unless 'unsigned int' is less than 32 bits).
 
11983
         */
 
11984
        return (unsigned int) d;
 
11985
}
 
11986
 
 
11987
unsigned int duk_to_uint16(duk_context *ctx, int index) {
 
11988
        duk_hthread *thr = (duk_hthread *) ctx;
 
11989
        duk_tval *tv;
 
11990
        duk_tval tv_temp;
 
11991
        double d;
 
11992
 
 
11993
        DUK_ASSERT(ctx != NULL);
 
11994
 
 
11995
        tv = duk_require_tval(ctx, index);
 
11996
        DUK_ASSERT(tv != NULL);
 
11997
        d = (double) duk_js_touint16(thr, tv);
 
11998
 
 
11999
        /* must relookup */
 
12000
        tv = duk_require_tval(ctx, index);
 
12001
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
12002
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
12003
        DUK_TVAL_DECREF(thr, &tv_temp);
 
12004
 
 
12005
        /* ToUint32() should already have restricted the result to
 
12006
         * an acceptable range (unless 'unsigned int' is less than 32 bits).
 
12007
         */
 
12008
        return (unsigned int) d;
 
12009
}
 
12010
 
 
12011
const char *duk_to_lstring(duk_context *ctx, int index, size_t *out_len) {
 
12012
        duk_to_string(ctx, index);
 
12013
        return duk_require_lstring(ctx, index, out_len);
 
12014
}
 
12015
 
 
12016
static int duk__safe_to_string_raw(duk_context *ctx) {
 
12017
        duk_to_string(ctx, -1);
 
12018
        return 1;
 
12019
}
 
12020
 
 
12021
const char *duk_safe_to_lstring(duk_context *ctx, int index, size_t *out_len) {
 
12022
        index = duk_require_normalize_index(ctx, index);
 
12023
 
 
12024
        /* We intentionally ignore the duk_safe_call() return value and only
 
12025
         * check the output type.  This way we don't also need to check that
 
12026
         * the returned value is indeed a string in the success case.
 
12027
         */
 
12028
 
 
12029
        duk_dup(ctx, index);
 
12030
        (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
 
12031
        if (!duk_is_string(ctx, -1)) {
 
12032
                /* Error: try coercing error to string once. */
 
12033
                (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
 
12034
                if (!duk_is_string(ctx, -1)) {
 
12035
                        /* Double error */
 
12036
                        duk_pop(ctx);
 
12037
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
 
12038
                } else {
 
12039
                        ;
 
12040
                }
 
12041
        } else {
 
12042
                ;
 
12043
        }
 
12044
        DUK_ASSERT(duk_is_string(ctx, -1));
 
12045
 
 
12046
        duk_replace(ctx, index);
 
12047
        return duk_require_lstring(ctx, index, out_len);
 
12048
}
 
12049
 
 
12050
/* FIXME: other variants like uint, u32 etc */
 
12051
int duk_to_int_clamped_raw(duk_context *ctx, int index, int minval, int maxval, int *out_clamped) {
 
12052
        duk_hthread *thr = (duk_hthread *) ctx;
 
12053
        duk_tval *tv;
 
12054
        duk_tval tv_temp;
 
12055
        double d;
 
12056
        int clamped = 0;
 
12057
 
 
12058
        DUK_ASSERT(ctx != NULL);
 
12059
 
 
12060
        tv = duk_require_tval(ctx, index);
 
12061
        DUK_ASSERT(tv != NULL);
 
12062
        d = duk_js_tointeger(thr, tv);  /* E5 Section 9.4, ToInteger() */
 
12063
 
 
12064
        if (d < (double) minval) {
 
12065
                clamped = 1;
 
12066
                d = (double) minval;
 
12067
        } else if (d > (double) maxval) {
 
12068
                clamped = 1;
 
12069
                d = (double) maxval;
 
12070
        }
 
12071
 
 
12072
        /* relookup in case duk_js_tointeger() ends up e.g. coercing an object */
 
12073
        tv = duk_require_tval(ctx, index);
 
12074
        DUK_TVAL_SET_TVAL(&tv_temp, tv);
 
12075
        DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
 
12076
        DUK_TVAL_DECREF(thr, &tv_temp);
 
12077
 
 
12078
        if (out_clamped) {
 
12079
                *out_clamped = clamped;
 
12080
        } else {
 
12081
                /* coerced value is updated to value stack even when RangeError thrown */
 
12082
                if (clamped) {
 
12083
                        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "number outside range");
 
12084
                }
 
12085
        }
 
12086
 
 
12087
        return (int) d;
 
12088
}
 
12089
 
 
12090
int duk_to_int_clamped(duk_context *ctx, int index, int minval, int maxval) {
 
12091
        int dummy;
 
12092
        return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
 
12093
}
 
12094
 
 
12095
int duk_to_int_check_range(duk_context *ctx, int index, int minval, int maxval) {
 
12096
        return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL);  /* NULL -> RangeError */
 
12097
}
 
12098
 
 
12099
const char *duk_to_string(duk_context *ctx, int index) {
 
12100
        duk_tval *tv;
 
12101
 
 
12102
        DUK_ASSERT(ctx != NULL);
 
12103
 
 
12104
        index = duk_require_normalize_index(ctx, index);
 
12105
 
 
12106
        tv = duk_require_tval(ctx, index);
 
12107
        DUK_ASSERT(tv != NULL);
 
12108
 
 
12109
        switch (DUK_TVAL_GET_TAG(tv)) {
 
12110
        case DUK_TAG_UNDEFINED: {
 
12111
                duk_push_hstring_stridx(ctx, DUK_STRIDX_UNDEFINED);
 
12112
                break;
 
12113
        }
 
12114
        case DUK_TAG_NULL: {
 
12115
                duk_push_hstring_stridx(ctx, DUK_STRIDX_NULL);
 
12116
                break;
 
12117
        }
 
12118
        case DUK_TAG_BOOLEAN: {
 
12119
                if (DUK_TVAL_GET_BOOLEAN(tv)) {
 
12120
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
 
12121
                } else {
 
12122
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
 
12123
                }
 
12124
                break;
 
12125
        }
 
12126
        case DUK_TAG_STRING: {
 
12127
                /* nop */
 
12128
                goto skip_replace;
 
12129
        }
 
12130
        case DUK_TAG_OBJECT: {
 
12131
                duk_to_primitive(ctx, index, DUK_HINT_STRING);
 
12132
                return duk_to_string(ctx, index);  /* Note: recursive call */
 
12133
        }
 
12134
        case DUK_TAG_BUFFER: {
 
12135
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
12136
 
 
12137
                /* Note: this allows creation of internal strings. */
 
12138
 
 
12139
                DUK_ASSERT(h != NULL);
 
12140
                duk_push_lstring(ctx,
 
12141
                                 (const char *) DUK_HBUFFER_GET_DATA_PTR(h),
 
12142
                                 (unsigned int) DUK_HBUFFER_GET_SIZE(h));
 
12143
                break;
 
12144
        }
 
12145
        case DUK_TAG_POINTER: {
 
12146
                void *ptr = DUK_TVAL_GET_POINTER(tv);
 
12147
                if (ptr != NULL) {
 
12148
                        duk_push_sprintf(ctx, "%p", ptr);
 
12149
                } else {
 
12150
                        /* Represent a null pointer as 'null' to be consistent with
 
12151
                         * the JSONX format variant.  Native '%p' format for a NULL
 
12152
                         * pointer may be e.g. '(nil)'.
 
12153
                         */
 
12154
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_NULL);
 
12155
                }
 
12156
                break;
 
12157
        }
 
12158
        default: {
 
12159
                /* number */
 
12160
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
12161
                duk_push_tval(ctx, tv);
 
12162
                duk_numconv_stringify(ctx,
 
12163
                                      10 /*radix*/,
 
12164
                                      0 /*precision:shortest*/,
 
12165
                                      0 /*force_exponential*/);
 
12166
                break;
 
12167
        }
 
12168
        }
 
12169
 
 
12170
        duk_replace(ctx, index);
 
12171
 
 
12172
 skip_replace:
 
12173
        return duk_require_string(ctx, index);
 
12174
}
 
12175
 
 
12176
/* internal */
 
12177
duk_hstring *duk_to_hstring(duk_context *ctx, int index) {
 
12178
        duk_hstring *ret;
 
12179
        DUK_ASSERT(ctx != NULL);
 
12180
        duk_to_string(ctx, index);
 
12181
        ret = duk_get_hstring(ctx, index);
 
12182
        DUK_ASSERT(ret != NULL);
 
12183
        return ret;
 
12184
}
 
12185
 
 
12186
void *duk_to_buffer(duk_context *ctx, int index, size_t *out_size) {
 
12187
        duk_hbuffer *h_buf;
 
12188
 
 
12189
        index = duk_require_normalize_index(ctx, index);
 
12190
 
 
12191
        if (duk_is_buffer(ctx, index)) {
 
12192
                /* Buffer is kept as is: note that fixed/dynamic nature of
 
12193
                 * the buffer is not changed.
 
12194
                 */
 
12195
        } else {
 
12196
                /* Non-buffer value is first ToString() coerced, then converted to
 
12197
                 * a fixed size buffer.
 
12198
                 */
 
12199
                duk_hstring *h_str;
 
12200
                void *buf;
 
12201
 
 
12202
                duk_to_string(ctx, index);
 
12203
                h_str = duk_get_hstring(ctx, index);
 
12204
                DUK_ASSERT(h_str != NULL);
 
12205
 
 
12206
                buf = duk_push_fixed_buffer(ctx, DUK_HSTRING_GET_BYTELEN(h_str));
 
12207
                DUK_ASSERT(buf != NULL);
 
12208
                DUK_MEMCPY(buf, DUK_HSTRING_GET_DATA(h_str), DUK_HSTRING_GET_BYTELEN(h_str));
 
12209
                duk_replace(ctx, index);
 
12210
        }
 
12211
 
 
12212
        h_buf = duk_get_hbuffer(ctx, index);
 
12213
        DUK_ASSERT(h_buf != NULL);
 
12214
        /* SCANBUILD: scan-build produces a NULL pointer dereference warning
 
12215
         * below; it never actually triggers because h_buf is actually never
 
12216
         * NULL.
 
12217
         */
 
12218
 
 
12219
        if (out_size) {
 
12220
                *out_size = DUK_HBUFFER_GET_SIZE(h_buf);
 
12221
        }
 
12222
        return DUK_HBUFFER_GET_DATA_PTR(h_buf);
 
12223
}
 
12224
 
 
12225
void *duk_to_pointer(duk_context *ctx, int index) {
 
12226
        duk_tval *tv;
 
12227
        void *res;
 
12228
 
 
12229
        DUK_ASSERT(ctx != NULL);
 
12230
 
 
12231
        index = duk_require_normalize_index(ctx, index);
 
12232
 
 
12233
        tv = duk_require_tval(ctx, index);
 
12234
        DUK_ASSERT(tv != NULL);
 
12235
 
 
12236
        switch (DUK_TVAL_GET_TAG(tv)) {
 
12237
        case DUK_TAG_UNDEFINED:
 
12238
        case DUK_TAG_NULL:
 
12239
        case DUK_TAG_BOOLEAN:
 
12240
                res = NULL;
 
12241
                break;
 
12242
        case DUK_TAG_POINTER:
 
12243
                res = DUK_TVAL_GET_POINTER(tv);
 
12244
                break;
 
12245
        case DUK_TAG_STRING:
 
12246
        case DUK_TAG_OBJECT:
 
12247
        case DUK_TAG_BUFFER:
 
12248
                /* heap allocated: return heap pointer which is NOT useful
 
12249
                 * for the caller, except for debugging.
 
12250
                 */
 
12251
                res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
 
12252
                break;
 
12253
        default:
 
12254
                /* number */
 
12255
                res = NULL;
 
12256
                break;
 
12257
        }
 
12258
 
 
12259
        duk_push_pointer(ctx, res);
 
12260
        duk_replace(ctx, index);
 
12261
        return res;
 
12262
}
 
12263
 
 
12264
void duk_to_object(duk_context *ctx, int index) {
 
12265
        duk_hthread *thr = (duk_hthread *) ctx;
 
12266
        duk_tval *tv;
 
12267
        int shared_flags = 0;   /* shared flags for a subset of types */
 
12268
        int shared_proto = 0;
 
12269
 
 
12270
        DUK_ASSERT(ctx != NULL);
 
12271
 
 
12272
        index = duk_require_normalize_index(ctx, index);
 
12273
 
 
12274
        tv = duk_require_tval(ctx, index);
 
12275
        DUK_ASSERT(tv != NULL);
 
12276
 
 
12277
        switch (DUK_TVAL_GET_TAG(tv)) {
 
12278
        case DUK_TAG_UNDEFINED:
 
12279
        case DUK_TAG_NULL: {
 
12280
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "attempt to coerce incompatible value to object");
 
12281
                break;
 
12282
        }
 
12283
        case DUK_TAG_BOOLEAN: {
 
12284
                shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
12285
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
 
12286
                shared_proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
 
12287
                goto create_object;
 
12288
        }
 
12289
        case DUK_TAG_STRING: {
 
12290
                shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
12291
                               DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ |
 
12292
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
 
12293
                shared_proto = DUK_BIDX_STRING_PROTOTYPE;
 
12294
                goto create_object;
 
12295
        }
 
12296
        case DUK_TAG_OBJECT: {
 
12297
                /* nop */
 
12298
                break;
 
12299
        }
 
12300
        case DUK_TAG_BUFFER: {
 
12301
                shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
12302
                               DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ |
 
12303
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER);
 
12304
                shared_proto = DUK_BIDX_BUFFER_PROTOTYPE;
 
12305
                goto create_object;
 
12306
        }
 
12307
        case DUK_TAG_POINTER: {
 
12308
                shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
12309
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
 
12310
                shared_proto = DUK_BIDX_POINTER_PROTOTYPE;
 
12311
                goto create_object;
 
12312
        }
 
12313
        default: {
 
12314
                shared_flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
12315
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
 
12316
                shared_proto = DUK_BIDX_NUMBER_PROTOTYPE;
 
12317
                goto create_object;
 
12318
        }
 
12319
        }
 
12320
        return;
 
12321
 
 
12322
 create_object:
 
12323
        (void) duk_push_object_helper(ctx, shared_flags, shared_proto);
 
12324
 
 
12325
        /* Note: Boolean prototype's internal value property is not writable,
 
12326
         * but duk_def_prop_stridx() disregards the write protection.  Boolean
 
12327
         * instances are immutable.
 
12328
         *
 
12329
         * String and buffer special behaviors are already enabled which is not
 
12330
         * ideal, but a write to the internal value is not affected by them.
 
12331
         */
 
12332
        duk_dup(ctx, index);
 
12333
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
 
12334
 
 
12335
        duk_replace(ctx, index);
 
12336
}
 
12337
 
 
12338
/*
 
12339
 *  Type checking
 
12340
 */
 
12341
 
 
12342
static int duk__tag_check(duk_context *ctx, int index, int tag) {
 
12343
        duk_tval *tv;
 
12344
 
 
12345
        tv = duk_get_tval(ctx, index);
 
12346
        if (!tv) {
 
12347
                return 0;
 
12348
        }
 
12349
        return (DUK_TVAL_GET_TAG(tv) == tag);
 
12350
}
 
12351
 
 
12352
static int duk__obj_flag_any_default_false(duk_context *ctx, int index, int flag_mask) {
 
12353
        duk_hobject *obj;
 
12354
 
 
12355
        DUK_ASSERT(ctx != NULL);
 
12356
 
 
12357
        obj = duk_get_hobject(ctx, index);
 
12358
        if (obj) {
 
12359
                return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
 
12360
        }
 
12361
        return 0;
 
12362
}
 
12363
 
 
12364
int duk_get_type(duk_context *ctx, int index) {
 
12365
        duk_tval *tv;
 
12366
 
 
12367
        tv = duk_get_tval(ctx, index);
 
12368
        if (!tv) {
 
12369
                return DUK_TYPE_NONE;
 
12370
        }
 
12371
        switch (DUK_TVAL_GET_TAG(tv)) {
 
12372
        case DUK_TAG_UNDEFINED:
 
12373
                return DUK_TYPE_UNDEFINED;
 
12374
        case DUK_TAG_NULL:
 
12375
                return DUK_TYPE_NULL;
 
12376
        case DUK_TAG_BOOLEAN:
 
12377
                return DUK_TYPE_BOOLEAN;
 
12378
        case DUK_TAG_STRING:
 
12379
                return DUK_TYPE_STRING;
 
12380
        case DUK_TAG_OBJECT:
 
12381
                return DUK_TYPE_OBJECT;
 
12382
        case DUK_TAG_BUFFER:
 
12383
                return DUK_TYPE_BUFFER;
 
12384
        case DUK_TAG_POINTER:
 
12385
                return DUK_TYPE_POINTER;
 
12386
        default:
 
12387
                /* Note: number has no explicit tag (in 8-byte representation) */
 
12388
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
12389
                return DUK_TYPE_NUMBER;
 
12390
        }
 
12391
        DUK_UNREACHABLE();
 
12392
}
 
12393
 
 
12394
int duk_check_type(duk_context *ctx, int index, int type) {
 
12395
        return (duk_get_type(ctx, index) == type) ? 1 : 0;
 
12396
}
 
12397
 
 
12398
int duk_get_type_mask(duk_context *ctx, int index) {
 
12399
        duk_tval *tv;
 
12400
 
 
12401
        tv = duk_get_tval(ctx, index);
 
12402
        if (!tv) {
 
12403
                return DUK_TYPE_MASK_NONE;
 
12404
        }
 
12405
        switch (DUK_TVAL_GET_TAG(tv)) {
 
12406
        case DUK_TAG_UNDEFINED:
 
12407
                return DUK_TYPE_MASK_UNDEFINED;
 
12408
        case DUK_TAG_NULL:
 
12409
                return DUK_TYPE_MASK_NULL;
 
12410
        case DUK_TAG_BOOLEAN:
 
12411
                return DUK_TYPE_MASK_BOOLEAN;
 
12412
        case DUK_TAG_STRING:
 
12413
                return DUK_TYPE_MASK_STRING;
 
12414
        case DUK_TAG_OBJECT:
 
12415
                return DUK_TYPE_MASK_OBJECT;
 
12416
        case DUK_TAG_BUFFER:
 
12417
                return DUK_TYPE_MASK_BUFFER;
 
12418
        case DUK_TAG_POINTER:
 
12419
                return DUK_TYPE_MASK_POINTER;
 
12420
        default:
 
12421
                /* Note: number has no explicit tag (in 8-byte representation) */
 
12422
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
12423
                return DUK_TYPE_MASK_NUMBER;
 
12424
        }
 
12425
        DUK_UNREACHABLE();
 
12426
}
 
12427
 
 
12428
int duk_check_type_mask(duk_context *ctx, int index, int mask) {
 
12429
        return (duk_get_type_mask(ctx, index) & mask) ? 1 : 0;
 
12430
}
 
12431
 
 
12432
int duk_is_undefined(duk_context *ctx, int index) {
 
12433
        DUK_ASSERT(ctx != NULL);
 
12434
        return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
 
12435
}
 
12436
 
 
12437
int duk_is_null(duk_context *ctx, int index) {
 
12438
        DUK_ASSERT(ctx != NULL);
 
12439
        return duk__tag_check(ctx, index, DUK_TAG_NULL);
 
12440
}
 
12441
 
 
12442
int duk_is_null_or_undefined(duk_context *ctx, int index) {
 
12443
        duk_tval *tv;
 
12444
 
 
12445
        tv = duk_get_tval(ctx, index);
 
12446
        if (!tv) {
 
12447
                return 0;
 
12448
        }
 
12449
        return (DUK_TVAL_GET_TAG(tv) == DUK_TAG_UNDEFINED) ||
 
12450
               (DUK_TVAL_GET_TAG(tv) == DUK_TAG_NULL);
 
12451
}
 
12452
 
 
12453
int duk_is_boolean(duk_context *ctx, int index) {
 
12454
        DUK_ASSERT(ctx != NULL);
 
12455
        return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
 
12456
}
 
12457
 
 
12458
int duk_is_number(duk_context *ctx, int index) {
 
12459
        duk_tval *tv;
 
12460
 
 
12461
        DUK_ASSERT(ctx != NULL);
 
12462
 
 
12463
        /*
 
12464
         *  Number is special because it doesn't have a specific
 
12465
         *  tag in the 8-byte representation.
 
12466
         */
 
12467
 
 
12468
        /* XXX: shorter version for 12-byte representation? */
 
12469
 
 
12470
        tv = duk_get_tval(ctx, index);
 
12471
        if (!tv) {
 
12472
                return 0;
 
12473
        }
 
12474
        return DUK_TVAL_IS_NUMBER(tv);
 
12475
}
 
12476
 
 
12477
int duk_is_nan(duk_context *ctx, int index) {
 
12478
        /* XXX: This will now return false for non-numbers, even though they would
 
12479
         * coerce to NaN (as a general rule).  In particular, duk_get_number()
 
12480
         * returns a NaN for non-numbers, so should this function also return
 
12481
         * true for non-numbers?
 
12482
         */
 
12483
 
 
12484
        duk_tval *tv;
 
12485
 
 
12486
        tv = duk_get_tval(ctx, index);
 
12487
        if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
 
12488
                return 0;
 
12489
        }
 
12490
        return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
 
12491
}
 
12492
 
 
12493
int duk_is_string(duk_context *ctx, int index) {
 
12494
        DUK_ASSERT(ctx != NULL);
 
12495
        return duk__tag_check(ctx, index, DUK_TAG_STRING);
 
12496
}
 
12497
 
 
12498
int duk_is_object(duk_context *ctx, int index) {
 
12499
        DUK_ASSERT(ctx != NULL);
 
12500
        return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
 
12501
}
 
12502
 
 
12503
int duk_is_buffer(duk_context *ctx, int index) {
 
12504
        DUK_ASSERT(ctx != NULL);
 
12505
        return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
 
12506
}
 
12507
 
 
12508
int duk_is_pointer(duk_context *ctx, int index) {
 
12509
        DUK_ASSERT(ctx != NULL);
 
12510
        return duk__tag_check(ctx, index, DUK_TAG_POINTER);
 
12511
}
 
12512
 
 
12513
int duk_is_array(duk_context *ctx, int index) {
 
12514
        duk_hobject *obj;
 
12515
 
 
12516
        DUK_ASSERT(ctx != NULL);
 
12517
 
 
12518
        obj = duk_get_hobject(ctx, index);
 
12519
        if (obj) {
 
12520
                return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
 
12521
        }
 
12522
        return 0;
 
12523
}
 
12524
 
 
12525
int duk_is_function(duk_context *ctx, int index) {
 
12526
        return duk__obj_flag_any_default_false(ctx,
 
12527
                                               index,
 
12528
                                               DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
 
12529
                                               DUK_HOBJECT_FLAG_NATIVEFUNCTION |
 
12530
                                               DUK_HOBJECT_FLAG_BOUND);
 
12531
}
 
12532
 
 
12533
int duk_is_c_function(duk_context *ctx, int index) {
 
12534
        return duk__obj_flag_any_default_false(ctx,
 
12535
                                               index,
 
12536
                                               DUK_HOBJECT_FLAG_NATIVEFUNCTION);
 
12537
}
 
12538
 
 
12539
int duk_is_ecmascript_function(duk_context *ctx, int index) {
 
12540
        return duk__obj_flag_any_default_false(ctx,
 
12541
                                               index,
 
12542
                                               DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
 
12543
}
 
12544
 
 
12545
int duk_is_bound_function(duk_context *ctx, int index) {
 
12546
        return duk__obj_flag_any_default_false(ctx,
 
12547
                                               index,
 
12548
                                               DUK_HOBJECT_FLAG_BOUND);
 
12549
}
 
12550
 
 
12551
int duk_is_thread(duk_context *ctx, int index) {
 
12552
        return duk__obj_flag_any_default_false(ctx,
 
12553
                                               index,
 
12554
                                               DUK_HOBJECT_FLAG_THREAD);
 
12555
}
 
12556
 
 
12557
int duk_is_callable(duk_context *ctx, int index) {
 
12558
        /* XXX: currently same as duk_is_function() */
 
12559
        return duk__obj_flag_any_default_false(ctx,
 
12560
                                               index,
 
12561
                                               DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
 
12562
                                               DUK_HOBJECT_FLAG_NATIVEFUNCTION |
 
12563
                                               DUK_HOBJECT_FLAG_BOUND);
 
12564
}
 
12565
 
 
12566
int duk_is_dynamic(duk_context *ctx, int index) {
 
12567
        duk_tval *tv;
 
12568
 
 
12569
        DUK_ASSERT(ctx != NULL);
 
12570
 
 
12571
        tv = duk_get_tval(ctx, index);
 
12572
        if (DUK_TVAL_IS_BUFFER(tv)) {
 
12573
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
12574
                DUK_ASSERT(h != NULL);
 
12575
                return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 1 : 0);
 
12576
        }
 
12577
        return 0;
 
12578
}
 
12579
 
 
12580
int duk_is_fixed(duk_context *ctx, int index) {
 
12581
        duk_tval *tv;
 
12582
 
 
12583
        DUK_ASSERT(ctx != NULL);
 
12584
 
 
12585
        tv = duk_get_tval(ctx, index);
 
12586
        if (DUK_TVAL_IS_BUFFER(tv)) {
 
12587
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
12588
                DUK_ASSERT(h != NULL);
 
12589
                return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
 
12590
        }
 
12591
        return 0;
 
12592
}
 
12593
 
 
12594
int duk_is_primitive(duk_context *ctx, int index) {
 
12595
        return !duk_is_object(ctx, index);
 
12596
}
 
12597
 
 
12598
int duk_is_object_coercible(duk_context *ctx, int index) {
 
12599
        return duk_check_type_mask(ctx, index, DUK_TYPE_MASK_BOOLEAN |
 
12600
                                               DUK_TYPE_MASK_NUMBER |
 
12601
                                               DUK_TYPE_MASK_STRING |
 
12602
                                               DUK_TYPE_MASK_OBJECT |
 
12603
                                               DUK_TYPE_MASK_BUFFER |
 
12604
                                               DUK_TYPE_MASK_POINTER);
 
12605
}
 
12606
 
 
12607
/*
 
12608
 *  Pushers
 
12609
 */
 
12610
 
 
12611
/* internal */
 
12612
void duk_push_tval(duk_context *ctx, duk_tval *tv) {
 
12613
        duk_hthread *thr = (duk_hthread *) ctx;
 
12614
        duk_tval *tv_slot;
 
12615
 
 
12616
        DUK_ASSERT(ctx != NULL);
 
12617
        DUK_ASSERT(tv != NULL);
 
12618
 
 
12619
        if (thr->valstack_top >= thr->valstack_end) {
 
12620
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
12621
        }
 
12622
 
 
12623
        tv_slot = thr->valstack_top;
 
12624
        DUK_TVAL_SET_TVAL(tv_slot, tv);
 
12625
        DUK_TVAL_INCREF(thr, tv);
 
12626
        thr->valstack_top++;
 
12627
}
 
12628
 
 
12629
/* internal */
 
12630
void duk_push_unused(duk_context *ctx) {
 
12631
        duk_tval tv;
 
12632
        DUK_ASSERT(ctx != NULL);
 
12633
        DUK_TVAL_SET_UNDEFINED_ACTUAL(&tv);
 
12634
        duk_push_tval(ctx, &tv);
 
12635
}
 
12636
 
 
12637
void duk_push_undefined(duk_context *ctx) {
 
12638
        duk_tval tv;
 
12639
        DUK_ASSERT(ctx != NULL);
 
12640
        DUK_TVAL_SET_UNDEFINED_ACTUAL(&tv);  /* XXX: heap constant would be nice */
 
12641
        duk_push_tval(ctx, &tv);
 
12642
}
 
12643
 
 
12644
void duk_push_null(duk_context *ctx) {
 
12645
        duk_tval tv;
 
12646
        DUK_ASSERT(ctx != NULL);
 
12647
        DUK_TVAL_SET_NULL(&tv);  /* XXX: heap constant would be nice */
 
12648
        duk_push_tval(ctx, &tv);
 
12649
}
 
12650
 
 
12651
void duk_push_boolean(duk_context *ctx, int val) {
 
12652
        duk_tval tv;
 
12653
        int b = (val ? 1 : 0);
 
12654
        DUK_ASSERT(ctx != NULL);
 
12655
        DUK_TVAL_SET_BOOLEAN(&tv, b);
 
12656
        duk_push_tval(ctx, &tv);
 
12657
}
 
12658
 
 
12659
void duk_push_true(duk_context *ctx) {
 
12660
        duk_push_boolean(ctx, 1);
 
12661
}
 
12662
 
 
12663
void duk_push_false(duk_context *ctx) {
 
12664
        duk_push_boolean(ctx, 0);
 
12665
}
 
12666
 
 
12667
void duk_push_number(duk_context *ctx, double val) {
 
12668
        duk_tval tv;
 
12669
        duk_double_union du;
 
12670
        DUK_ASSERT(ctx != NULL);
 
12671
 
 
12672
        /* normalize NaN which may not match our canonical internal NaN */
 
12673
        du.d = val;
 
12674
        DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
12675
 
 
12676
        DUK_TVAL_SET_NUMBER(&tv, du.d);
 
12677
        duk_push_tval(ctx, &tv);
 
12678
}
 
12679
 
 
12680
void duk_push_int(duk_context *ctx, int val) {
 
12681
        duk_push_number(ctx, (double) val);
 
12682
}
 
12683
 
 
12684
void duk_push_u32(duk_context *ctx, duk_uint32_t val) {
 
12685
        duk_push_number(ctx, (double) val);
 
12686
}
 
12687
 
 
12688
void duk_push_nan(duk_context *ctx) {
 
12689
        duk_push_number(ctx, DUK_DOUBLE_NAN);
 
12690
}
 
12691
 
 
12692
const char *duk_push_lstring(duk_context *ctx, const char *str, size_t len) {
 
12693
        duk_hthread *thr = (duk_hthread *) ctx;
 
12694
        duk_hstring *h;
 
12695
        duk_tval *tv_slot;
 
12696
 
 
12697
        DUK_ASSERT(ctx != NULL);
 
12698
 
 
12699
        /* check stack before interning (avoid hanging temp) */
 
12700
        if (thr->valstack_top >= thr->valstack_end) {
 
12701
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
12702
        }
 
12703
 
 
12704
        /* NULL with zero length represents an empty string; NULL with higher
 
12705
         * length is also now trated like an empty string although it is
 
12706
         * a bit dubious.  This is unlike duk_push_string() which pushes a
 
12707
         * 'null' if the input string is a NULL.
 
12708
         */
 
12709
        if (!str) {
 
12710
                len = 0;
 
12711
        }
 
12712
 
 
12713
        /* Check for maximum string length */
 
12714
        if (len > DUK_HSTRING_MAX_BYTELEN) {
 
12715
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "string too long");
 
12716
        }
 
12717
 
 
12718
        h = duk_heap_string_intern_checked(thr, (duk_uint8_t *) str, (duk_uint32_t) len);
 
12719
        DUK_ASSERT(h != NULL);
 
12720
 
 
12721
        tv_slot = thr->valstack_top;
 
12722
        DUK_TVAL_SET_STRING(tv_slot, h);
 
12723
        DUK_HSTRING_INCREF(thr, h);
 
12724
        thr->valstack_top++;
 
12725
 
 
12726
        return (const char *) DUK_HSTRING_GET_DATA(h);
 
12727
}
 
12728
 
 
12729
const char *duk_push_string(duk_context *ctx, const char *str) {
 
12730
        DUK_ASSERT(ctx != NULL);
 
12731
 
 
12732
        if (str) {
 
12733
                return duk_push_lstring(ctx, str, DUK_STRLEN(str));
 
12734
        } else {
 
12735
                duk_push_null(ctx);
 
12736
                return NULL;
 
12737
        }
 
12738
}
 
12739
 
 
12740
#ifdef DUK_USE_FILE_IO
 
12741
/* This is a bit clunky because it is ANSI C portable.  Should perhaps
 
12742
 * relocate to another file because this is potentially platform
 
12743
 * dependent.
 
12744
 */
 
12745
const char *duk_push_string_file(duk_context *ctx, const char *path) {
 
12746
        duk_hthread *thr = (duk_hthread *) ctx;
 
12747
        duk_file *f = NULL;
 
12748
        char *buf;
 
12749
        long sz;
 
12750
 
 
12751
        DUK_ASSERT(ctx != NULL);
 
12752
        if (!path) {
 
12753
                goto fail;
 
12754
        }
 
12755
        f = DUK_FOPEN(path, "rb");
 
12756
        if (!f) {
 
12757
                goto fail;
 
12758
        }
 
12759
        if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
 
12760
                goto fail;
 
12761
        }
 
12762
        sz = DUK_FTELL(f);
 
12763
        if (sz < 0) {
 
12764
                goto fail;
 
12765
        }
 
12766
        if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
 
12767
                goto fail;
 
12768
        }
 
12769
        buf = (char *) duk_push_fixed_buffer(ctx, (size_t) sz);
 
12770
        DUK_ASSERT(buf != NULL);
 
12771
        if (DUK_FREAD(buf, 1, sz, f) != (size_t) sz) {
 
12772
                goto fail;
 
12773
        }
 
12774
        (void) DUK_FCLOSE(f);  /* ignore fclose() error */
 
12775
        f = NULL;
 
12776
        return duk_to_string(ctx, -1);
 
12777
 
 
12778
 fail:
 
12779
        if (f) {
 
12780
                DUK_FCLOSE(f);
 
12781
        }
 
12782
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "failed to read file");
 
12783
        return NULL;
 
12784
}
 
12785
#else
 
12786
const char *duk_push_string_file(duk_context *ctx, const char *path) {
 
12787
        duk_hthread *thr = (duk_hthread *) ctx;
 
12788
        DUK_ASSERT(ctx != NULL);
 
12789
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "file I/O disabled");
 
12790
        return NULL;
 
12791
}
 
12792
#endif  /* DUK_USE_FILE_IO */
 
12793
 
 
12794
void duk_push_pointer(duk_context *ctx, void *val) {
 
12795
        duk_tval tv;
 
12796
        DUK_ASSERT(ctx != NULL);
 
12797
 
 
12798
        DUK_TVAL_SET_POINTER(&tv, val);
 
12799
        duk_push_tval(ctx, &tv);
 
12800
}
 
12801
 
 
12802
#if 0  /* FIXME: unused */
 
12803
void duk_push_multiple(duk_context *ctx, const char *types, ...) {
 
12804
        va_list ap;
 
12805
        duk_hthread *thr;
 
12806
        const char *p;
 
12807
 
 
12808
        DUK_ASSERT(ctx != NULL);
 
12809
        DUK_ASSERT(types != NULL);
 
12810
 
 
12811
        thr = (duk_hthread *) ctx;
 
12812
 
 
12813
        va_start(ap, types);
 
12814
 
 
12815
        p = types;
 
12816
        for (;;) {
 
12817
                unsigned int ch = (unsigned int) (*p++);
 
12818
                switch (ch) {
 
12819
                case 'u': {
 
12820
                        (void) duk_push_undefined(ctx);
 
12821
                        break;
 
12822
                }
 
12823
                case 'n': {
 
12824
                        (void) duk_push_null(ctx);
 
12825
                        break;
 
12826
                }
 
12827
                case 'b': {
 
12828
                        int val = va_arg(ap, int);
 
12829
                        (void) duk_push_boolean(ctx, val);
 
12830
                        break;
 
12831
                }
 
12832
                case 'd': {
 
12833
                        double val = va_arg(ap, double);
 
12834
                        (void) duk_push_number(ctx, val);
 
12835
                        break;
 
12836
                }
 
12837
                case 'i': {
 
12838
                        int val = va_arg(ap, int);
 
12839
                        (void) duk_push_int(ctx, val);
 
12840
                        break;
 
12841
                }
 
12842
                case 's': {
 
12843
                        const char *val = va_arg(ap, const char *);
 
12844
                        (void) duk_push_string(ctx, val);
 
12845
                        break;
 
12846
                }
 
12847
                case 'l': {
 
12848
                        const char *val = va_arg(ap, const char *);
 
12849
                        size_t len = va_arg(ap, size_t);
 
12850
                        (void) duk_push_lstring(ctx, val, len);
 
12851
                        break;
 
12852
                }
 
12853
                case 'p': {
 
12854
                        void *val = va_arg(ap, void *);
 
12855
                        (void) duk_push_pointer(ctx, val);
 
12856
                        break;
 
12857
                }
 
12858
                case 0: {
 
12859
                        goto done;
 
12860
                }
 
12861
                default: {
 
12862
                        DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid type char: %d", ch);
 
12863
                }
 
12864
                }
 
12865
        }
 
12866
 done:
 
12867
 
 
12868
        va_end(ap);
 
12869
}
 
12870
#endif  /* FIXME: unused */
 
12871
 
 
12872
#define DUK__PUSH_THIS_FLAG_CHECK_COERC  (1 << 0)
 
12873
#define DUK__PUSH_THIS_FLAG_TO_OBJECT    (1 << 1)
 
12874
#define DUK__PUSH_THIS_FLAG_TO_STRING    (1 << 2)
 
12875
 
 
12876
static void duk__push_this_helper(duk_context *ctx, int flags) {
 
12877
        duk_hthread *thr = (duk_hthread *) ctx;
 
12878
 
 
12879
        DUK_ASSERT(thr != NULL);
 
12880
        DUK_ASSERT(ctx != NULL);
 
12881
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);  /* avoid warning (unsigned) */
 
12882
        DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
 
12883
 
 
12884
        if (thr->callstack_top == 0) {
 
12885
                if (flags & DUK__PUSH_THIS_FLAG_CHECK_COERC) {
 
12886
                        goto type_error;
 
12887
                }
 
12888
                duk_push_undefined(ctx);
 
12889
        } else {
 
12890
                duk_tval tv_tmp;
 
12891
                duk_tval *tv;
 
12892
 
 
12893
                /* 'this' binding is just before current activation's bottom */
 
12894
                DUK_ASSERT(thr->valstack_bottom > thr->valstack);
 
12895
                tv = thr->valstack_bottom - 1;
 
12896
                if (flags & DUK__PUSH_THIS_FLAG_CHECK_COERC) {
 
12897
                        if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
 
12898
                                goto type_error;
 
12899
                        }
 
12900
                }
 
12901
 
 
12902
                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
12903
                duk_push_tval(ctx, &tv_tmp);
 
12904
        }
 
12905
 
 
12906
        if (flags & DUK__PUSH_THIS_FLAG_TO_OBJECT) {
 
12907
                duk_to_object(ctx, -1);
 
12908
        } else if (flags & DUK__PUSH_THIS_FLAG_TO_STRING) {
 
12909
                duk_to_string(ctx, -1);
 
12910
        }
 
12911
 
 
12912
        return;
 
12913
 
 
12914
 type_error:
 
12915
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not object coercible");
 
12916
}
 
12917
 
 
12918
void duk_push_this(duk_context *ctx) {
 
12919
        duk__push_this_helper(ctx, 0 /*flags*/);
 
12920
}
 
12921
 
 
12922
void duk_push_this_check_object_coercible(duk_context *ctx) {
 
12923
        duk__push_this_helper(ctx, DUK__PUSH_THIS_FLAG_CHECK_COERC /*flags*/);
 
12924
}
 
12925
 
 
12926
duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
 
12927
        duk_hobject *h;
 
12928
        duk__push_this_helper(ctx, DUK__PUSH_THIS_FLAG_CHECK_COERC |
 
12929
                                   DUK__PUSH_THIS_FLAG_TO_OBJECT /*flags*/);
 
12930
        h = duk_get_hobject(ctx, -1);
 
12931
        DUK_ASSERT(h != NULL);
 
12932
        return h;
 
12933
}
 
12934
 
 
12935
duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
 
12936
        duk_hstring *h;
 
12937
        duk__push_this_helper(ctx, DUK__PUSH_THIS_FLAG_CHECK_COERC |
 
12938
                                   DUK__PUSH_THIS_FLAG_TO_STRING /*flags*/);
 
12939
        h = duk_get_hstring(ctx, -1);
 
12940
        DUK_ASSERT(h != NULL);
 
12941
        return h;
 
12942
}
 
12943
 
 
12944
void duk_push_current_function(duk_context *ctx) {
 
12945
        duk_hthread *thr = (duk_hthread *) ctx;
 
12946
 
 
12947
        DUK_ASSERT(thr != NULL);
 
12948
        DUK_ASSERT(ctx != NULL);
 
12949
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
 
12950
        DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
 
12951
 
 
12952
        if (thr->callstack_top == 0) {
 
12953
                duk_push_undefined(ctx);
 
12954
        } else {
 
12955
                duk_activation *act = thr->callstack + thr->callstack_top - 1;
 
12956
                DUK_ASSERT(act->func != NULL);
 
12957
                duk_push_hobject(ctx, act->func);
 
12958
        }
 
12959
}
 
12960
 
 
12961
void duk_push_current_thread(duk_context *ctx) {
 
12962
        duk_hthread *thr = (duk_hthread *) ctx;
 
12963
 
 
12964
        DUK_ASSERT(thr != NULL);
 
12965
        DUK_ASSERT(ctx != NULL);
 
12966
 
 
12967
        if (thr->heap->curr_thread) {
 
12968
                duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
 
12969
        } else {
 
12970
                duk_push_undefined(ctx);
 
12971
        }
 
12972
}
 
12973
 
 
12974
void duk_push_global_object(duk_context *ctx) {
 
12975
        duk_hthread *thr = (duk_hthread *) ctx;
 
12976
 
 
12977
        DUK_ASSERT(thr != NULL);
 
12978
        DUK_ASSERT(ctx != NULL);
 
12979
 
 
12980
        duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
 
12981
}
 
12982
 
 
12983
/* XXX: size optimize */
 
12984
static void duk__push_stash(duk_context *ctx) {
 
12985
        DUK_ASSERT(ctx != NULL);
 
12986
        if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
 
12987
                DUK_DDDPRINT("creating heap/global/thread stash on first use");
 
12988
                duk_pop(ctx);
 
12989
                duk_push_object_internal(ctx);
 
12990
                duk_dup_top(ctx);
 
12991
                duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C);  /* [ ... parent stash stash ] -> [ ... parent stash ] */
 
12992
        }
 
12993
        duk_remove(ctx, -2);
 
12994
}
 
12995
 
 
12996
void duk_push_heap_stash(duk_context *ctx) {
 
12997
        duk_hthread *thr = (duk_hthread *) ctx;
 
12998
        duk_heap *heap;
 
12999
        DUK_ASSERT(ctx != NULL);
 
13000
        heap = thr->heap;
 
13001
        DUK_ASSERT(heap->heap_object != NULL);
 
13002
        duk_push_hobject(ctx, heap->heap_object);
 
13003
        duk__push_stash(ctx);
 
13004
}
 
13005
 
 
13006
void duk_push_global_stash(duk_context *ctx) {
 
13007
        DUK_ASSERT(ctx != NULL);
 
13008
        duk_push_global_object(ctx);
 
13009
        duk__push_stash(ctx);
 
13010
}
 
13011
 
 
13012
void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
 
13013
        duk_hthread *thr = (duk_hthread *) ctx;
 
13014
        DUK_ASSERT(ctx != NULL);
 
13015
        if (!target_ctx) {
 
13016
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid argument(s)");
 
13017
                return;  /* not reached */
 
13018
        }
 
13019
        duk_push_hobject(ctx, (duk_hobject *) target_ctx);
 
13020
        duk__push_stash(ctx);
 
13021
}
 
13022
 
 
13023
static int duk__try_push_vsprintf(duk_context *ctx, void *buf, size_t sz, const char *fmt, va_list ap) {
 
13024
        int len;
 
13025
 
 
13026
        DUK_UNREF(ctx);
 
13027
 
 
13028
        /* NUL terminator handling doesn't matter here */
 
13029
        len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
 
13030
        if ((size_t) len < sz) {
 
13031
                return len;
 
13032
        }
 
13033
        return -1;
 
13034
}
 
13035
 
 
13036
const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
 
13037
        duk_hthread *thr = (duk_hthread *) ctx;
 
13038
        size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
 
13039
        void *buf;
 
13040
        int len;
 
13041
        const char *res;
 
13042
 
 
13043
        DUK_ASSERT(ctx != NULL);
 
13044
 
 
13045
        /* special handling of fmt==NULL */
 
13046
        if (!fmt) {
 
13047
                duk_hstring *h_str;
 
13048
                duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
13049
                h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);  /* rely on interning, must be this string */
 
13050
                return (const char *) DUK_HSTRING_GET_DATA(h_str);
 
13051
        }
 
13052
 
 
13053
        /* initial estimate based on format string */
 
13054
        sz = DUK_STRLEN(fmt) + 16;  /* XXX: plus something to avoid just missing */
 
13055
        if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
 
13056
                sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
 
13057
        }
 
13058
        DUK_ASSERT(sz > 0);
 
13059
 
 
13060
        buf = duk_push_dynamic_buffer(ctx, sz);
 
13061
 
 
13062
        for (;;) {
 
13063
                len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap);
 
13064
                if (len >= 0) {
 
13065
                        break;
 
13066
                }
 
13067
 
 
13068
                /* failed, resize and try again */
 
13069
                sz = sz * 2;
 
13070
                if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
 
13071
                        DUK_ERROR(thr, DUK_ERR_API_ERROR, "cannot sprintf, required buffer insanely long");
 
13072
                }
 
13073
 
 
13074
                buf = duk_resize_buffer(ctx, -1, sz);
 
13075
                DUK_ASSERT(buf != NULL);
 
13076
        }
 
13077
 
 
13078
        /* Cannot use duk_to_string() on the buffer because it is usually
 
13079
         * larger than 'len'.
 
13080
         */
 
13081
        res = duk_push_lstring(ctx, (const char *) buf, (size_t) len);  /* [buf res] */
 
13082
        duk_remove(ctx, -2);
 
13083
        return res;
 
13084
}
 
13085
 
 
13086
const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
 
13087
        va_list ap;
 
13088
        const char *retval;
 
13089
 
 
13090
        /* allow fmt==NULL */
 
13091
        va_start(ap, fmt);
 
13092
        retval = duk_push_vsprintf(ctx, fmt, ap);
 
13093
        va_end(ap);
 
13094
 
 
13095
        return retval;
 
13096
}
 
13097
 
 
13098
/* internal */
 
13099
int duk_push_object_helper(duk_context *ctx, int hobject_flags_and_class, int prototype_bidx) {
 
13100
        duk_hthread *thr = (duk_hthread *) ctx;
 
13101
        duk_tval *tv_slot;
 
13102
        duk_hobject *h;
 
13103
        int ret;
 
13104
 
 
13105
        DUK_ASSERT(ctx != NULL);
 
13106
        DUK_ASSERT(prototype_bidx == -1 ||
 
13107
                   (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
 
13108
 
 
13109
        /* check stack before interning (avoid hanging temp) */
 
13110
        if (thr->valstack_top >= thr->valstack_end) {
 
13111
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
13112
        }
 
13113
 
 
13114
        h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
 
13115
        if (!h) {
 
13116
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate an object");
 
13117
        }
 
13118
 
 
13119
        DUK_DDDPRINT("created object with flags: 0x%08x", h->hdr.h_flags);
 
13120
 
 
13121
        tv_slot = thr->valstack_top;
 
13122
        DUK_TVAL_SET_OBJECT(tv_slot, h);
 
13123
        DUK_HOBJECT_INCREF(thr, h);
 
13124
        ret = (int) (thr->valstack_top - thr->valstack_bottom);
 
13125
        thr->valstack_top++;
 
13126
 
 
13127
        /* object is now reachable */
 
13128
 
 
13129
        if (prototype_bidx >= 0) {
 
13130
                DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
 
13131
        } else {
 
13132
                DUK_ASSERT(prototype_bidx == -1);
 
13133
                DUK_ASSERT(h->prototype == NULL);
 
13134
        }
 
13135
 
 
13136
        return ret;
 
13137
}
 
13138
 
 
13139
int duk_push_object_helper_proto(duk_context *ctx, int hobject_flags_and_class, duk_hobject *proto) {
 
13140
        duk_hthread *thr = (duk_hthread *) ctx;
 
13141
        int ret;
 
13142
        duk_hobject *h;
 
13143
 
 
13144
        ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
 
13145
        h = duk_get_hobject(ctx, -1);
 
13146
        DUK_ASSERT(h != NULL);
 
13147
        DUK_ASSERT(h->prototype == NULL);
 
13148
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
 
13149
        return ret;
 
13150
}
 
13151
 
 
13152
int duk_push_object(duk_context *ctx) {
 
13153
        return duk_push_object_helper(ctx,
 
13154
                                      DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13155
                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
13156
                                      DUK_BIDX_OBJECT_PROTOTYPE);
 
13157
}
 
13158
 
 
13159
int duk_push_array(duk_context *ctx) {
 
13160
        duk_hthread *thr = (duk_hthread *) ctx;
 
13161
        duk_hobject *obj;
 
13162
        int ret;
 
13163
 
 
13164
        ret = duk_push_object_helper(ctx,
 
13165
                                     DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13166
                                     DUK_HOBJECT_FLAG_ARRAY_PART |
 
13167
                                     DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
 
13168
                                     DUK_BIDX_ARRAY_PROTOTYPE);
 
13169
 
 
13170
        obj = duk_require_hobject(ctx, ret);
 
13171
 
 
13172
        /*
 
13173
         *  An array must have a 'length' property (E5 Section 15.4.5.2).
 
13174
         *  The special array behavior flag must only be enabled once the
 
13175
         *  length property has been added.
 
13176
         */
 
13177
 
 
13178
        duk_push_number(ctx, 0.0);
 
13179
        duk_hobject_define_property_internal(thr,
 
13180
                                             obj,
 
13181
                                             DUK_HTHREAD_STRING_LENGTH(thr),
 
13182
                                             DUK_PROPDESC_FLAGS_W);
 
13183
        DUK_HOBJECT_SET_SPECIAL_ARRAY(obj);
 
13184
 
 
13185
        return ret;
 
13186
}
 
13187
 
 
13188
int duk_push_thread_raw(duk_context *ctx, int flags) {
 
13189
        duk_hthread *thr = (duk_hthread *) ctx;
 
13190
        duk_hthread *obj;
 
13191
        int ret;
 
13192
        duk_tval *tv_slot;
 
13193
 
 
13194
        DUK_ASSERT(ctx != NULL);
 
13195
 
 
13196
        /* check stack before interning (avoid hanging temp) */
 
13197
        if (thr->valstack_top >= thr->valstack_end) {
 
13198
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
13199
        }
 
13200
 
 
13201
        obj = duk_hthread_alloc(thr->heap,
 
13202
                                DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13203
                                DUK_HOBJECT_FLAG_THREAD |
 
13204
                                DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
 
13205
        if (!obj) {
 
13206
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate a thread object");
 
13207
        }
 
13208
        obj->state = DUK_HTHREAD_STATE_INACTIVE;
 
13209
        obj->strs = thr->strs;
 
13210
        DUK_DDDPRINT("created thread object with flags: 0x%08x", obj->obj.hdr.h_flags);
 
13211
 
 
13212
        /* make the new thread reachable */
 
13213
        tv_slot = thr->valstack_top;
 
13214
        DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
 
13215
        DUK_HTHREAD_INCREF(thr, obj);
 
13216
        ret = (int) (thr->valstack_top - thr->valstack_bottom);
 
13217
        thr->valstack_top++;
 
13218
 
 
13219
        /* important to do this *after* pushing, to make the thread reachable for gc */
 
13220
        if (!duk_hthread_init_stacks(thr->heap, obj)) {
 
13221
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate thread");
 
13222
        }
 
13223
 
 
13224
        /* initialize built-ins - either by copying or creating new ones */
 
13225
        if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
 
13226
                duk_hthread_create_builtin_objects(obj);
 
13227
        } else {
 
13228
                duk_hthread_copy_builtin_objects(thr, obj);
 
13229
        }
 
13230
 
 
13231
        /* default prototype (Note: 'obj' must be reachable) */
 
13232
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
 
13233
 
 
13234
        /* Initial stack size satisfies the stack spare constraints so there
 
13235
         * is no need to require stack here.
 
13236
         */
 
13237
        DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
 
13238
                   DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
 
13239
 
 
13240
        return ret;
 
13241
}
 
13242
 
 
13243
int duk_push_compiledfunction(duk_context *ctx) {
 
13244
        duk_hthread *thr = (duk_hthread *) ctx;
 
13245
        duk_hcompiledfunction *obj;
 
13246
        int ret;
 
13247
        duk_tval *tv_slot;
 
13248
 
 
13249
        DUK_ASSERT(ctx != NULL);
 
13250
 
 
13251
        /* check stack before interning (avoid hanging temp) */
 
13252
        if (thr->valstack_top >= thr->valstack_end) {
 
13253
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
13254
        }
 
13255
 
 
13256
        /* Template functions are not strictly constructable (they don't
 
13257
         * have a "prototype" property for instance), so leave the
 
13258
         * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
 
13259
         */
 
13260
 
 
13261
        obj = duk_hcompiledfunction_alloc(thr->heap,
 
13262
                                          DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13263
                                          DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
 
13264
                                          DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
 
13265
        if (!obj) {
 
13266
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate a function object");
 
13267
        }
 
13268
 
 
13269
        DUK_DDDPRINT("created compiled function object with flags: 0x%08x", obj->obj.hdr.h_flags);
 
13270
 
 
13271
        tv_slot = thr->valstack_top;
 
13272
        DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
 
13273
        DUK_HOBJECT_INCREF(thr, obj);
 
13274
        ret = (int) (thr->valstack_top - thr->valstack_bottom);
 
13275
        thr->valstack_top++;
 
13276
 
 
13277
        /* default prototype (Note: 'obj' must be reachable) */
 
13278
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
 
13279
 
 
13280
        return ret;
 
13281
}
 
13282
 
 
13283
static int duk__push_c_function_raw(duk_context *ctx, duk_c_function func, int nargs, duk_uint32_t flags) {
 
13284
        duk_hthread *thr = (duk_hthread *) ctx;
 
13285
        duk_hnativefunction *obj;
 
13286
        int ret;
 
13287
        duk_tval *tv_slot;
 
13288
        duk_uint16_t func_nargs;
 
13289
 
 
13290
        DUK_ASSERT(ctx != NULL);
 
13291
 
 
13292
        /* check stack before interning (avoid hanging temp) */
 
13293
        if (thr->valstack_top >= thr->valstack_end) {
 
13294
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
13295
        }
 
13296
        if (func == NULL) {
 
13297
                goto api_error;
 
13298
        }
 
13299
        if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
 
13300
                func_nargs = (duk_uint16_t) nargs;
 
13301
        } else if (nargs == DUK_VARARGS) {
 
13302
                func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
 
13303
        } else {
 
13304
                goto api_error;
 
13305
        }
 
13306
 
 
13307
        /* DUK_HOBJECT_FLAG_CONSTRUCTABLE is not currently set; native functions
 
13308
         * are not constructable unless explicitly defined as such.
 
13309
         *
 
13310
         * DUK_HOBJECT_FLAG_NEWENV is currently always set; native functions
 
13311
         * cannot e.g. declare variables to caller's scope.
 
13312
         */
 
13313
 
 
13314
        obj = duk_hnativefunction_alloc(thr->heap, flags);
 
13315
        if (!obj) {
 
13316
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate a function object");
 
13317
        }
 
13318
 
 
13319
        obj->func = func;
 
13320
        obj->nargs = func_nargs;
 
13321
 
 
13322
        DUK_DDDPRINT("created native function object with flags: 0x%08x, nargs=%d", obj->obj.hdr.h_flags, obj->nargs);
 
13323
 
 
13324
        tv_slot = thr->valstack_top;
 
13325
        DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
 
13326
        DUK_HOBJECT_INCREF(thr, obj);
 
13327
        ret = (int) (thr->valstack_top - thr->valstack_bottom);
 
13328
        thr->valstack_top++;
 
13329
 
 
13330
        /* default prototype (Note: 'obj' must be reachable) */
 
13331
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
 
13332
 
 
13333
        return ret;
 
13334
 
 
13335
 api_error:
 
13336
        DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid argument(s)");
 
13337
        return 0;  /* not reached */
 
13338
}
 
13339
 
 
13340
int duk_push_c_function(duk_context *ctx, duk_c_function func, int nargs) {
 
13341
        duk_uint32_t flags;
 
13342
 
 
13343
        flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13344
                DUK_HOBJECT_FLAG_CONSTRUCTABLE |
 
13345
                DUK_HOBJECT_FLAG_NATIVEFUNCTION |
 
13346
                DUK_HOBJECT_FLAG_NEWENV |
 
13347
                DUK_HOBJECT_FLAG_STRICT |
 
13348
                DUK_HOBJECT_FLAG_SPECIAL_DUKFUNC |
 
13349
                DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
 
13350
        
 
13351
        return duk__push_c_function_raw(ctx, func, nargs, flags);
 
13352
}
 
13353
 
 
13354
void duk_push_c_function_nospecial(duk_context *ctx, duk_c_function func, int nargs) {
 
13355
        duk_uint32_t flags;
 
13356
 
 
13357
        flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13358
                DUK_HOBJECT_FLAG_CONSTRUCTABLE |
 
13359
                DUK_HOBJECT_FLAG_NATIVEFUNCTION |
 
13360
                DUK_HOBJECT_FLAG_NEWENV |
 
13361
                DUK_HOBJECT_FLAG_STRICT |
 
13362
                DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
 
13363
        
 
13364
        (void) duk__push_c_function_raw(ctx, func, nargs, flags);
 
13365
}
 
13366
 
 
13367
void duk_push_c_function_noconstruct_nospecial(duk_context *ctx, duk_c_function func, int nargs) {
 
13368
        duk_uint32_t flags;
 
13369
 
 
13370
        flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13371
                DUK_HOBJECT_FLAG_NATIVEFUNCTION |
 
13372
                DUK_HOBJECT_FLAG_NEWENV |
 
13373
                DUK_HOBJECT_FLAG_STRICT |
 
13374
                DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
 
13375
        
 
13376
        (void) duk__push_c_function_raw(ctx, func, nargs, flags);
 
13377
}
 
13378
 
 
13379
static int duk__push_error_object_vsprintf(duk_context *ctx, int err_code, const char *filename, int line, const char *fmt, va_list ap) {
 
13380
        duk_hthread *thr = (duk_hthread *) ctx;
 
13381
        int retval;
 
13382
        duk_hobject *proto;
 
13383
#ifdef DUK_USE_AUGMENT_ERROR_CREATE
 
13384
        int noblame_fileline;
 
13385
#endif
 
13386
 
 
13387
        DUK_ASSERT(ctx != NULL);
 
13388
        DUK_ASSERT(thr != NULL);
 
13389
 
 
13390
        /* Error code also packs a tracedata related flag. */
 
13391
#ifdef DUK_USE_AUGMENT_ERROR_CREATE
 
13392
        noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
 
13393
#endif
 
13394
        err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
 
13395
 
 
13396
        /* error gets its 'name' from the prototype */
 
13397
        proto = duk_error_prototype_from_code(thr, err_code);
 
13398
        retval = duk_push_object_helper_proto(ctx,
 
13399
                                              DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13400
                                              DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
 
13401
                                              proto);
 
13402
 
 
13403
        /* ... and its 'message' from an instance property */
 
13404
        if (fmt) {
 
13405
                duk_push_vsprintf(ctx, fmt, ap);
 
13406
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
 
13407
        } else {
 
13408
                /* If no explicit message given, put error code into message field
 
13409
                 * (as a number).  This is not fully in keeping with the Ecmascript
 
13410
                 * error model because messages are supposed to be strings (Error
 
13411
                 * constructors use ToString() on their argument).  However, it's
 
13412
                 * probably more useful than having a separate 'code' property.
 
13413
                 */
 
13414
                duk_push_int(ctx, err_code);
 
13415
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
 
13416
        }
 
13417
 
 
13418
#if 0
 
13419
        /* Disabled for now, not sure this is a useful property */
 
13420
        duk_push_int(ctx, err_code);
 
13421
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_CODE, DUK_PROPDESC_FLAGS_WC);
 
13422
#endif
 
13423
 
 
13424
        /* Creation time error augmentation */
 
13425
#ifdef DUK_USE_AUGMENT_ERROR_CREATE
 
13426
        /* filename may be NULL in which case file/line is not recorded */
 
13427
        duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline);  /* may throw an error */
 
13428
#endif
 
13429
 
 
13430
        return retval;
 
13431
}
 
13432
 
 
13433
int duk_push_error_object_raw(duk_context *ctx, int err_code, const char *filename, int line, const char *fmt, ...) {
 
13434
        va_list ap;
 
13435
        int ret;
 
13436
 
 
13437
        va_start(ap, fmt);
 
13438
        ret = duk__push_error_object_vsprintf(ctx, err_code, filename, line, fmt, ap);
 
13439
        va_end(ap);
 
13440
        return ret;
 
13441
}
 
13442
 
 
13443
#ifndef DUK_USE_VARIADIC_MACROS
 
13444
int duk_push_error_object_stash(duk_context *ctx, int err_code, const char *fmt, ...) {
 
13445
        const char *filename = duk_api_global_filename;
 
13446
        int line = duk_api_global_line;
 
13447
        va_list ap;
 
13448
        int ret;
 
13449
 
 
13450
        duk_api_global_filename = NULL;
 
13451
        duk_api_global_line = 0;
 
13452
        va_start(ap, fmt);
 
13453
        ret = duk__push_error_object_vsprintf(ctx, err_code, filename, line, fmt, ap);
 
13454
        va_end(ap);
 
13455
        return ret;
 
13456
}
 
13457
#endif
 
13458
 
 
13459
/* FIXME: repetition, see duk_push_object */
 
13460
void *duk_push_buffer(duk_context *ctx, size_t size, int dynamic) {
 
13461
        duk_hthread *thr = (duk_hthread *) ctx;
 
13462
        duk_tval *tv_slot;
 
13463
        duk_hbuffer *h;
 
13464
 
 
13465
        DUK_ASSERT(ctx != NULL);
 
13466
 
 
13467
        /* check stack before interning (avoid hanging temp) */
 
13468
        if (thr->valstack_top >= thr->valstack_end) {
 
13469
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to push beyond currently allocated stack");
 
13470
        }
 
13471
 
 
13472
        /* Check for maximum buffer length. */
 
13473
        if (size > DUK_HBUFFER_MAX_BYTELEN) {
 
13474
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "buffer too long");
 
13475
        }
 
13476
 
 
13477
        h = duk_hbuffer_alloc(thr->heap, size, dynamic);
 
13478
        if (!h) {
 
13479
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate buffer");
 
13480
        }
 
13481
 
 
13482
        tv_slot = thr->valstack_top;
 
13483
        DUK_TVAL_SET_BUFFER(tv_slot, h);
 
13484
        DUK_HBUFFER_INCREF(thr, h);
 
13485
        thr->valstack_top++;
 
13486
 
 
13487
        return DUK_HBUFFER_GET_DATA_PTR(h);
 
13488
}
 
13489
 
 
13490
void *duk_push_fixed_buffer(duk_context *ctx, size_t size) {
 
13491
        return duk_push_buffer(ctx, size, 0);
 
13492
}
 
13493
 
 
13494
void *duk_push_dynamic_buffer(duk_context *ctx, size_t size) {
 
13495
        return duk_push_buffer(ctx, size, 1);
 
13496
}
 
13497
 
 
13498
int duk_push_object_internal(duk_context *ctx) {
 
13499
        return duk_push_object_helper(ctx,
 
13500
                                      DUK_HOBJECT_FLAG_EXTENSIBLE |
 
13501
                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
13502
                                      -1);  /* no prototype */
 
13503
}
 
13504
 
 
13505
/* internal */
 
13506
void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
 
13507
        duk_tval tv;
 
13508
        DUK_ASSERT(ctx != NULL);
 
13509
        DUK_ASSERT(h != NULL);
 
13510
        DUK_TVAL_SET_STRING(&tv, h);
 
13511
        duk_push_tval(ctx, &tv);
 
13512
}
 
13513
 
 
13514
void duk_push_hstring_stridx(duk_context *ctx, int stridx) {
 
13515
        duk_hthread *thr = (duk_hthread *) ctx;
 
13516
        DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
 
13517
        duk_push_hstring(ctx, thr->strs[stridx]);
 
13518
}
 
13519
 
 
13520
/* internal */
 
13521
void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
 
13522
        duk_tval tv;
 
13523
        DUK_ASSERT(ctx != NULL);
 
13524
        DUK_ASSERT(h != NULL);
 
13525
        DUK_TVAL_SET_OBJECT(&tv, h);
 
13526
        duk_push_tval(ctx, &tv);
 
13527
}
 
13528
 
 
13529
/* internal */
 
13530
void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
 
13531
        duk_tval tv;
 
13532
        DUK_ASSERT(ctx != NULL);
 
13533
        DUK_ASSERT(h != NULL);
 
13534
        DUK_TVAL_SET_BUFFER(&tv, h);
 
13535
        duk_push_tval(ctx, &tv);
 
13536
}
 
13537
 
 
13538
/* internal */
 
13539
void duk_push_builtin(duk_context *ctx, int builtin_idx) {
 
13540
        duk_hthread *thr = (duk_hthread *) ctx;
 
13541
        DUK_ASSERT(ctx != NULL);
 
13542
        DUK_ASSERT(thr != NULL);
 
13543
        DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
 
13544
        DUK_ASSERT(thr->builtins[builtin_idx] != NULL);  /* FIXME: this assumption may need be to relaxed! */
 
13545
        duk_push_hobject(ctx, thr->builtins[builtin_idx]);
 
13546
}
 
13547
 
 
13548
/*
 
13549
 *  Poppers
 
13550
 */
 
13551
 
 
13552
void duk_pop_n(duk_context *ctx, unsigned int count) {
 
13553
        duk_hthread *thr = (duk_hthread *) ctx;
 
13554
        DUK_ASSERT(ctx != NULL);
 
13555
 
 
13556
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
13557
        if ((size_t) (thr->valstack_top - thr->valstack_bottom) < (size_t) count) {
 
13558
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "attempt to pop too many entries");
 
13559
        }
 
13560
 
 
13561
        /*
 
13562
         *  Must be very careful here, every DECREF may cause reallocation
 
13563
         *  of our valstack.
 
13564
         */
 
13565
 
 
13566
        /* FIXME: inlined DECREF macro would be nice here: no NULL check,
 
13567
         * refzero queueing but no refzero algorithm run (= no pointer
 
13568
         * instability), inline code.
 
13569
         */
 
13570
        
 
13571
#ifdef DUK_USE_REFERENCE_COUNTING
 
13572
        while (count > 0) {
 
13573
                duk_tval tv_tmp;
 
13574
                duk_tval *tv;
 
13575
 
 
13576
                thr->valstack_top--;
 
13577
                tv = thr->valstack_top;
 
13578
                DUK_ASSERT(tv >= thr->valstack_bottom);
 
13579
                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
13580
                DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
13581
                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
13582
                count--;
 
13583
        }
 
13584
#else
 
13585
        while (count > 0) {
 
13586
                duk_tval *tv;
 
13587
 
 
13588
                thr->valstack_top--;
 
13589
                tv = thr->valstack_top;
 
13590
                DUK_ASSERT(tv >= thr->valstack_bottom);
 
13591
                DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
13592
                count--;
 
13593
        }
 
13594
 
 
13595
#endif
 
13596
 
 
13597
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
13598
}
 
13599
 
 
13600
void duk_pop(duk_context *ctx) {
 
13601
        duk_pop_n(ctx, 1);
 
13602
}
 
13603
 
 
13604
void duk_pop_2(duk_context *ctx) {
 
13605
        duk_pop_n(ctx, 2);
 
13606
}
 
13607
 
 
13608
void duk_pop_3(duk_context *ctx) {
 
13609
        duk_pop_n(ctx, 3);
 
13610
}
 
13611
 
 
13612
/*
 
13613
 *  Error throwing
 
13614
 */
 
13615
 
 
13616
void duk_throw(duk_context *ctx) {
 
13617
        duk_hthread *thr = (duk_hthread *) ctx;
 
13618
 
 
13619
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
13620
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
13621
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
13622
 
 
13623
        if (thr->valstack_top == thr->valstack_bottom) {
 
13624
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "no value to throw");
 
13625
        }
 
13626
 
 
13627
        /* Errors are augmented when they are created, not when they are
 
13628
         * thrown or re-thrown.  The current error handler, however, runs
 
13629
         * just before an error is thrown.
 
13630
         */
 
13631
 
 
13632
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
13633
        DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", duk_get_tval(ctx, -1));
 
13634
        duk_err_augment_error_throw(thr);
 
13635
#endif
 
13636
        DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", duk_get_tval(ctx, -1));
 
13637
 
 
13638
        duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
 
13639
 
 
13640
        /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
 
13641
         * need to check that here.  If the value is NULL, a panic occurs because
 
13642
         * we can't return.
 
13643
         */
 
13644
 
 
13645
        duk_err_longjmp(thr);
 
13646
        DUK_UNREACHABLE();
 
13647
}
 
13648
 
 
13649
void duk_fatal(duk_context *ctx, int err_code, const char *err_msg) {
 
13650
        duk_hthread *thr = (duk_hthread *) ctx;
 
13651
 
 
13652
        DUK_ASSERT(ctx != NULL);
 
13653
        DUK_ASSERT(thr != NULL);
 
13654
        DUK_ASSERT(thr->heap != NULL);
 
13655
        DUK_ASSERT(thr->heap->fatal_func != NULL);
 
13656
 
 
13657
        DUK_DPRINT("fatal error occurred, code %d, message %s", err_code, err_msg);
 
13658
 
 
13659
        /* fatal_func should be noreturn, but noreturn declarations on function
 
13660
         * pointers has a very spotty support apparently so it's not currently
 
13661
         * done.
 
13662
         */
 
13663
        thr->heap->fatal_func(ctx, err_code, err_msg);
 
13664
 
 
13665
        DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
 
13666
}
 
13667
 
 
13668
void duk_error_raw(duk_context *ctx, int err_code, const char *filename, int line, const char *fmt, ...) {
 
13669
        va_list ap;
 
13670
        va_start(ap, fmt);
 
13671
        duk__push_error_object_vsprintf(ctx, err_code, filename, line, fmt, ap);
 
13672
        va_end(ap);
 
13673
        duk_throw(ctx);
 
13674
}
 
13675
 
 
13676
#ifndef DUK_USE_VARIADIC_MACROS
 
13677
void duk_error_stash(duk_context *ctx, int err_code, const char *fmt, ...) {
 
13678
        const char *filename = duk_api_global_filename;
 
13679
        int line = duk_api_global_line;
 
13680
        va_list ap;
 
13681
 
 
13682
        duk_api_global_filename = NULL;
 
13683
        duk_api_global_line = 0;
 
13684
 
 
13685
        va_start(ap, fmt);
 
13686
        duk__push_error_object_vsprintf(ctx, err_code, filename, line, fmt, ap);
 
13687
        va_end(ap);
 
13688
        duk_throw(ctx);
 
13689
}
 
13690
#endif
 
13691
 
 
13692
int duk_equals(duk_context *ctx, int index1, int index2) {
 
13693
        duk_hthread *thr = (duk_hthread *) ctx;
 
13694
        duk_tval *tv1, *tv2;
 
13695
 
 
13696
        tv1 = duk_get_tval(ctx, index1);
 
13697
        if (!tv1) {
 
13698
                return 0;
 
13699
        }
 
13700
        tv2 = duk_get_tval(ctx, index2);
 
13701
        if (!tv2) {
 
13702
                return 0;
 
13703
        }
 
13704
 
 
13705
        /* Coercion may be needed, the helper handles that by pushing the
 
13706
         * tagged values to the stack.
 
13707
         */
 
13708
        return duk_js_equals(thr, tv1, tv2);
 
13709
 
 
13710
}
 
13711
 
 
13712
int duk_strict_equals(duk_context *ctx, int index1, int index2) {
 
13713
        duk_tval *tv1, *tv2;
 
13714
 
 
13715
        tv1 = duk_get_tval(ctx, index1);
 
13716
        if (!tv1) {
 
13717
                return 0;
 
13718
        }
 
13719
        tv2 = duk_get_tval(ctx, index2);
 
13720
        if (!tv2) {
 
13721
                return 0;
 
13722
        }
 
13723
 
 
13724
        /* No coercions or other side effects, so safe */
 
13725
        return duk_js_strict_equals(tv1, tv2);
 
13726
}
 
13727
 
 
13728
/*
 
13729
 *  Heap creation
 
13730
 */
 
13731
 
 
13732
duk_context *duk_create_heap(duk_alloc_function alloc_func,
 
13733
                             duk_realloc_function realloc_func,
 
13734
                             duk_free_function free_func,
 
13735
                             void *alloc_udata,
 
13736
                             duk_fatal_function fatal_handler) {
 
13737
        duk_heap *heap = NULL;
 
13738
        duk_context *ctx;
 
13739
 
 
13740
        /* Assume that either all memory funcs are NULL or non-NULL, mixed
 
13741
         * cases will now be unsafe.
 
13742
         */
 
13743
 
 
13744
        /* FIXME: just assert non-NULL values here and make caller arguments
 
13745
         * do the defaulting to the default implementations (smaller code)?
 
13746
         */
 
13747
 
 
13748
        if (!alloc_func) {
 
13749
                DUK_ASSERT(realloc_func == NULL);
 
13750
                DUK_ASSERT(free_func == NULL);
 
13751
                alloc_func = duk_default_alloc_function;
 
13752
                realloc_func = duk_default_realloc_function;
 
13753
                free_func = duk_default_free_function;
 
13754
        } else {
 
13755
                DUK_ASSERT(realloc_func != NULL);
 
13756
                DUK_ASSERT(free_func != NULL);
 
13757
        }
 
13758
 
 
13759
        if (!fatal_handler) {
 
13760
                fatal_handler = duk_default_fatal_handler;
 
13761
        }
 
13762
 
 
13763
        DUK_ASSERT(alloc_func != NULL);
 
13764
        DUK_ASSERT(realloc_func != NULL);
 
13765
        DUK_ASSERT(free_func != NULL);
 
13766
        DUK_ASSERT(fatal_handler != NULL);
 
13767
 
 
13768
        heap = duk_heap_alloc(alloc_func, realloc_func, free_func, alloc_udata, fatal_handler);
 
13769
        if (!heap) {
 
13770
                return NULL;
 
13771
        }
 
13772
        ctx = (duk_context *) heap->heap_thread;
 
13773
        DUK_ASSERT(ctx != NULL);
 
13774
        DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
 
13775
        return ctx;
 
13776
}
 
13777
 
 
13778
void duk_destroy_heap(duk_context *ctx) {
 
13779
        duk_hthread *thr = (duk_hthread *) ctx;
 
13780
        duk_heap *heap;
 
13781
 
 
13782
        if (!ctx) {
 
13783
                return;
 
13784
        }
 
13785
        heap = thr->heap;
 
13786
        DUK_ASSERT(heap != NULL);
 
13787
 
 
13788
        duk_heap_free(heap);
 
13789
}
 
13790
 
 
13791
#line 1 "duk_api_buffer.c"
 
13792
/*
 
13793
 *  Buffer
 
13794
 */
 
13795
 
 
13796
/* include removed: duk_internal.h */
 
13797
 
 
13798
void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
 
13799
        duk_hthread *thr = (duk_hthread *) ctx;
 
13800
        duk_hbuffer_dynamic *h;
 
13801
 
 
13802
        DUK_ASSERT(ctx != NULL);
 
13803
 
 
13804
        h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
 
13805
        DUK_ASSERT(h != NULL);
 
13806
 
 
13807
        if (!DUK_HBUFFER_HAS_DYNAMIC(h)) {
 
13808
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "buffer is not dynamic");
 
13809
        }
 
13810
 
 
13811
        /* maximum size check is handled by callee */
 
13812
        duk_hbuffer_resize(thr, h, new_size, new_size);  /* snug */
 
13813
 
 
13814
        return DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h);
 
13815
}
 
13816
 
 
13817
void duk_to_fixed_buffer(duk_context *ctx, duk_idx_t index) {
 
13818
        duk_hbuffer_dynamic *h_src;
 
13819
        duk_uint8_t *data;
 
13820
        duk_size_t size;
 
13821
 
 
13822
        index = duk_require_normalize_index(ctx, index);
 
13823
 
 
13824
        h_src = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
 
13825
        DUK_ASSERT(h_src != NULL);
 
13826
        if (!DUK_HBUFFER_HAS_DYNAMIC(h_src)) {
 
13827
                return;
 
13828
        }
 
13829
 
 
13830
        size = DUK_HBUFFER_GET_SIZE(h_src);
 
13831
        data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, size);
 
13832
        if (size > 0U) {
 
13833
                DUK_ASSERT(data != NULL);
 
13834
                DUK_MEMCPY(data, DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h_src), size);
 
13835
        }
 
13836
 
 
13837
        duk_replace(ctx, index);
 
13838
}
 
13839
 
 
13840
#line 1 "duk_api_call.c"
 
13841
/*
 
13842
 *  Calls.
 
13843
 *
 
13844
 *  Protected variants should avoid ever throwing an error.
 
13845
 */
 
13846
 
 
13847
/* include removed: duk_internal.h */
 
13848
 
 
13849
/* Prepare value stack for a method call through an object property.
 
13850
 * May currently throw an error e.g. when getting the property.
 
13851
 */
 
13852
static void duk__call_prop_prep_stack(duk_context *ctx, int normalized_obj_index, int nargs) {
 
13853
        DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%d, nargs=%d, stacktop=%d",
 
13854
                     normalized_obj_index, nargs, duk_get_top(ctx));
 
13855
 
 
13856
        /* [... key arg1 ... argN] */
 
13857
 
 
13858
        /* duplicate key */
 
13859
        duk_dup(ctx, -nargs - 1);  /* Note: -nargs alone would fail for nargs == 0, this is OK */
 
13860
        duk_get_prop(ctx, normalized_obj_index);
 
13861
 
 
13862
        DUK_DDDPRINT("func: %!T", duk_get_tval(ctx, -1));
 
13863
 
 
13864
        /* [... key arg1 ... argN func] */
 
13865
 
 
13866
        duk_replace(ctx, -nargs - 2);
 
13867
 
 
13868
        /* [... func arg1 ... argN] */
 
13869
 
 
13870
        duk_dup(ctx, normalized_obj_index);
 
13871
        duk_insert(ctx, -nargs - 1);
 
13872
 
 
13873
        /* [... func this arg1 ... argN] */
 
13874
}
 
13875
 
 
13876
void duk_call(duk_context *ctx, int nargs) {
 
13877
        duk_hthread *thr = (duk_hthread *) ctx;
 
13878
        int call_flags;
 
13879
        int idx_func;
 
13880
        int rc;
 
13881
 
 
13882
        DUK_ASSERT(ctx != NULL);
 
13883
        DUK_ASSERT(thr != NULL);
 
13884
 
 
13885
        idx_func = duk_get_top(ctx) - nargs - 1;  /* must work for nargs <= 0 */
 
13886
        if (idx_func < 0 || nargs < 0) {
 
13887
                /* note that we can't reliably pop anything here */
 
13888
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid call args");
 
13889
        }
 
13890
 
 
13891
        /* awkward; we assume there is space for this */
 
13892
        duk_push_undefined(ctx);
 
13893
        duk_insert(ctx, idx_func + 1);
 
13894
 
 
13895
        call_flags = 0;  /* not protected, respect reclimit, not constructor */
 
13896
 
 
13897
        rc = duk_handle_call(thr,           /* thread */
 
13898
                             nargs,         /* num_stack_args */
 
13899
                             call_flags);   /* call_flags */
 
13900
        DUK_UNREF(rc);
 
13901
}
 
13902
 
 
13903
void duk_call_method(duk_context *ctx, int nargs) {
 
13904
        duk_hthread *thr = (duk_hthread *) ctx;
 
13905
        int call_flags;
 
13906
        int idx_func;
 
13907
        int rc;
 
13908
 
 
13909
        DUK_ASSERT(ctx != NULL);
 
13910
        DUK_ASSERT(thr != NULL);
 
13911
 
 
13912
        idx_func = duk_get_top(ctx) - nargs - 2;  /* must work for nargs <= 0 */
 
13913
        if (idx_func < 0 || nargs < 0) {
 
13914
                /* note that we can't reliably pop anything here */
 
13915
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid call args");
 
13916
        }
 
13917
 
 
13918
        call_flags = 0;  /* not protected, respect reclimit, not constructor */
 
13919
 
 
13920
        rc = duk_handle_call(thr,           /* thread */
 
13921
                             nargs,         /* num_stack_args */
 
13922
                             call_flags);   /* call_flags */
 
13923
        DUK_UNREF(rc);
 
13924
}
 
13925
 
 
13926
void duk_call_prop(duk_context *ctx, int obj_index, int nargs) {
 
13927
        /*
 
13928
         *  XXX: if duk_handle_call() took values through indices, this could be
 
13929
         *  made much more sensible.  However, duk_handle_call() needs to fudge
 
13930
         *  the 'this' and 'func' values to handle bound function chains, which
 
13931
         *  is now done "in-place", so this is not a trivial change.
 
13932
         */
 
13933
 
 
13934
        obj_index = duk_require_normalize_index(ctx, obj_index);  /* make absolute */
 
13935
 
 
13936
        duk__call_prop_prep_stack(ctx, obj_index, nargs);
 
13937
 
 
13938
        duk_call_method(ctx, nargs);
 
13939
}
 
13940
 
 
13941
int duk_pcall(duk_context *ctx, int nargs) {
 
13942
        duk_hthread *thr = (duk_hthread *) ctx;
 
13943
        int call_flags;
 
13944
        int idx_func;
 
13945
        int rc;
 
13946
 
 
13947
        DUK_ASSERT(ctx != NULL);
 
13948
        DUK_ASSERT(thr != NULL);
 
13949
 
 
13950
        idx_func = duk_get_top(ctx) - nargs - 1;  /* must work for nargs <= 0 */
 
13951
        if (idx_func < 0 || nargs < 0) {
 
13952
                /* We can't reliably pop anything here because the stack input
 
13953
                 * shape is incorrect.  So we throw an error; if the caller has
 
13954
                 * no catch point for this, a fatal error will occur.  Another
 
13955
                 * alternative would be to just return an error.  But then the
 
13956
                 * stack would be in an unknown state which might cause some
 
13957
                 * very hard to diagnose problems later on.  Also note that even
 
13958
                 * if we did not throw an error here, the underlying call handler
 
13959
                 * might STILL throw an out-of-memory error or some other internal
 
13960
                 * fatal error.
 
13961
                 */
 
13962
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid call args");
 
13963
                return DUK_EXEC_ERROR;  /* unreachable */
 
13964
        }
 
13965
 
 
13966
        /* awkward; we assume there is space for this */
 
13967
        duk_push_undefined(ctx);
 
13968
        duk_insert(ctx, idx_func + 1);
 
13969
 
 
13970
        call_flags = DUK_CALL_FLAG_PROTECTED;  /* protected, respect reclimit, not constructor */
 
13971
 
 
13972
        rc = duk_handle_call(thr,           /* thread */
 
13973
                             nargs,         /* num_stack_args */
 
13974
                             call_flags);   /* call_flags */
 
13975
 
 
13976
        return rc;
 
13977
}
 
13978
 
 
13979
int duk_pcall_method(duk_context *ctx, int nargs) {
 
13980
        duk_hthread *thr = (duk_hthread *) ctx;
 
13981
        int call_flags;
 
13982
        int idx_func;
 
13983
        int rc;
 
13984
 
 
13985
        DUK_ASSERT(ctx != NULL);
 
13986
        DUK_ASSERT(thr != NULL);
 
13987
 
 
13988
        idx_func = duk_get_top(ctx) - nargs - 2;  /* must work for nargs <= 0 */
 
13989
        if (idx_func < 0 || nargs < 0) {
 
13990
                /* See comments in duk_pcall(). */
 
13991
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid call args");
 
13992
                return DUK_EXEC_ERROR;  /* unreachable */
 
13993
        }
 
13994
 
 
13995
        call_flags = DUK_CALL_FLAG_PROTECTED;  /* protected, respect reclimit, not constructor */
 
13996
 
 
13997
        rc = duk_handle_call(thr,           /* thread */
 
13998
                             nargs,         /* num_stack_args */
 
13999
                             call_flags);   /* call_flags */
 
14000
 
 
14001
        return rc;
 
14002
}
 
14003
 
 
14004
static int duk__pcall_prop_raw(duk_context *ctx) {
 
14005
        int obj_index;
 
14006
        int nargs;
 
14007
 
 
14008
        /* Get the original arguments.  Note that obj_index may be a relative
 
14009
         * index so the stack must have the same top when we use it.
 
14010
         */
 
14011
 
 
14012
        obj_index = duk_get_int(ctx, -2);
 
14013
        nargs = duk_get_int(ctx, -1);
 
14014
        duk_pop_2(ctx);
 
14015
 
 
14016
        obj_index = duk_require_normalize_index(ctx, obj_index);  /* make absolute */
 
14017
        duk__call_prop_prep_stack(ctx, obj_index, nargs);
 
14018
        duk_call_method(ctx, nargs);
 
14019
        return 1;
 
14020
}
 
14021
 
 
14022
int duk_pcall_prop(duk_context *ctx, int obj_index, int nargs) {
 
14023
        /*
 
14024
         *  Must be careful to catch errors related to value stack manipulation
 
14025
         *  and property lookup, not just the call itself.
 
14026
         */
 
14027
 
 
14028
        duk_push_int(ctx, obj_index);
 
14029
        duk_push_int(ctx, nargs);
 
14030
 
 
14031
        /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
 
14032
         * If the value stack does not contain enough args, an error is thrown; this matches
 
14033
         * behavior of the other protected call API functions.
 
14034
         */
 
14035
        return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
 
14036
}
 
14037
 
 
14038
int duk_safe_call(duk_context *ctx, duk_safe_call_function func, int nargs, int nrets) {
 
14039
        duk_hthread *thr = (duk_hthread *) ctx;
 
14040
        int rc;
 
14041
 
 
14042
        DUK_ASSERT(ctx != NULL);
 
14043
        DUK_ASSERT(thr != NULL);
 
14044
 
 
14045
        if (duk_get_top(ctx) < nargs || nrets < 0) {
 
14046
                /* See comments in duk_pcall(). */
 
14047
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid call args");
 
14048
                return DUK_EXEC_ERROR;  /* unreachable */
 
14049
        }
 
14050
 
 
14051
        rc = duk_handle_safe_call(thr,           /* thread */
 
14052
                                  func,          /* func */
 
14053
                                  nargs,         /* num_stack_args */
 
14054
                                  nrets);        /* num_stack_res */
 
14055
 
 
14056
        return rc;
 
14057
}
 
14058
 
 
14059
void duk_new(duk_context *ctx, int nargs) {
 
14060
        /*
 
14061
         *  There are two [[Construct]] operations in the specification:
 
14062
         *
 
14063
         *    - E5 Section 13.2.2: for Function objects
 
14064
         *    - E5 Section 15.3.4.5.2: for "bound" Function objects
 
14065
         *
 
14066
         *  The chain of bound functions is resolved in Section 15.3.4.5.2,
 
14067
         *  with arguments "piling up" until the [[Construct]] internal
 
14068
         *  method is called on the final, actual Function object.  Note
 
14069
         *  that the "prototype" property is looked up *only* from the
 
14070
         *  final object, *before* calling the constructor.
 
14071
         *
 
14072
         *  Currently we follow the bound function chain here to get the
 
14073
         *  "prototype" property value from the final, non-bound function.
 
14074
         *  However, we let duk_handle_call() handle the argument "piling"
 
14075
         *  when the constructor is called.  The bound function chain is
 
14076
         *  thus now processed twice.
 
14077
         *
 
14078
         *  When constructing new Array instances, an unnecessary object is
 
14079
         *  created and discarded now: the standard [[Construct]] creates an
 
14080
         *  object, and calls the Array constructor.  The Array constructor
 
14081
         *  returns an Array instance, which is used as the result value for
 
14082
         *  the "new" operation; the object created before the Array constructor
 
14083
         *  call is discarded.
 
14084
         *
 
14085
         *  This would be easy to fix, e.g. by knowing that the Array constructor
 
14086
         *  will always create a replacement object and skip creating the fallback
 
14087
         *  object in that case.  FIXME.
 
14088
         *
 
14089
         *  Note: functions called via "new" need to know they are called as a
 
14090
         *  constructor.  For instance, built-in constructors behave differently
 
14091
         *  depending on how they are called.
 
14092
         */
 
14093
 
 
14094
        /* FIXME: should this go to duk_js_call.c? it implements core semantics. */
 
14095
 
 
14096
        duk_hthread *thr = (duk_hthread *) ctx;
 
14097
        duk_hobject *proto;
 
14098
        duk_hobject *cons;
 
14099
        duk_hobject *fallback;
 
14100
        int idx_cons;
 
14101
        int call_flags;
 
14102
        int rc;
 
14103
 
 
14104
        /* [... constructor arg1 ... argN] */
 
14105
 
 
14106
        idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
 
14107
 
 
14108
        DUK_DDDPRINT("top=%d, nargs=%d, idx_cons=%d", duk_get_top(ctx), nargs, idx_cons);
 
14109
 
 
14110
        /* FIXME: code duplication */
 
14111
 
 
14112
        /*
 
14113
         *  Figure out the final, non-bound constructor, to get "prototype"
 
14114
         *  property.
 
14115
         */
 
14116
 
 
14117
        duk_dup(ctx, idx_cons);
 
14118
        for (;;) {
 
14119
                cons = duk_get_hobject(ctx, -1);
 
14120
                if (cons == NULL || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
 
14121
                        /* Checking constructability from anything else than the
 
14122
                         * initial constructor is not strictly necessary, but a
 
14123
                         * nice sanity check.
 
14124
                         */
 
14125
                        goto not_constructable;
 
14126
                }
 
14127
                if (!DUK_HOBJECT_HAS_BOUND(cons)) {
 
14128
                        break;
 
14129
                }
 
14130
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);  /* -> [... cons target] */
 
14131
                duk_remove(ctx, -2);                                  /* -> [... target] */
 
14132
        }
 
14133
        DUK_ASSERT(cons != NULL && !DUK_HOBJECT_HAS_BOUND(cons));
 
14134
 
 
14135
        /* [... constructor arg1 ... argN final_cons] */
 
14136
 
 
14137
        /*
 
14138
         *  Create "fallback" object to be used as the object instance,
 
14139
         *  unless the constructor returns a replacement value.
 
14140
         *  Its internal prototype needs to be set based on "prototype"
 
14141
         *  property of the constructor.
 
14142
         */
 
14143
 
 
14144
        duk_push_object(ctx);  /* class Object, extensible */
 
14145
 
 
14146
        /* [... constructor arg1 ... argN final_cons fallback] */
 
14147
 
 
14148
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
 
14149
        proto = duk_get_hobject(ctx, -1);
 
14150
        if (!proto) {
 
14151
                DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
 
14152
                             "-> leave standard Object prototype as fallback prototype");
 
14153
        } else {
 
14154
                DUK_DDDPRINT("constructor has 'prototype' property with object value "
 
14155
                             "-> set fallback prototype to that value: %!iO", proto);
 
14156
                fallback = duk_get_hobject(ctx, -2);
 
14157
                DUK_ASSERT(fallback != NULL);
 
14158
                DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
 
14159
        }
 
14160
        duk_pop(ctx);
 
14161
 
 
14162
        /* [... constructor arg1 ... argN final_cons fallback] */
 
14163
 
 
14164
        /*
 
14165
         *  Manipulate callstack for the call.
 
14166
         */
 
14167
 
 
14168
        duk_dup_top(ctx);
 
14169
        duk_insert(ctx, idx_cons + 1);  /* use fallback as 'this' value */
 
14170
        duk_insert(ctx, idx_cons);      /* also stash it before constructor,
 
14171
                                         * in case we need it (as the fallback value)
 
14172
                                         */
 
14173
        duk_pop(ctx);                   /* pop final_cons */
 
14174
 
 
14175
 
 
14176
        /* [... fallback constructor fallback(this) arg1 ... argN];
 
14177
         * Note: idx_cons points to first 'fallback', not 'constructor'.
 
14178
         */
 
14179
 
 
14180
        DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
 
14181
                     "nargs=%d, top=%d",
 
14182
                     duk_get_tval(ctx, idx_cons + 1), duk_get_tval(ctx, idx_cons + 2),
 
14183
                     nargs, duk_get_top(ctx));
 
14184
 
 
14185
        /*
 
14186
         *  Call the constructor function (called in "constructor mode").
 
14187
         */
 
14188
 
 
14189
        call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL;  /* not protected, respect reclimit, is a constructor call */
 
14190
 
 
14191
        rc = duk_handle_call(thr,           /* thread */
 
14192
                             nargs,         /* num_stack_args */
 
14193
                             call_flags);   /* call_flags */
 
14194
        DUK_UNREF(rc);
 
14195
 
 
14196
        /* [... fallback retval] */
 
14197
 
 
14198
        DUK_DDDPRINT("constructor call finished, rc=%d, fallback=%!iT, retval=%!iT",
 
14199
                     rc, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
14200
 
 
14201
        /*
 
14202
         *  Determine whether to use the constructor return value as the created
 
14203
         *  object instance or not.
 
14204
         */
 
14205
 
 
14206
        if (duk_is_object(ctx, -1)) {
 
14207
                duk_remove(ctx, -2);
 
14208
        } else {
 
14209
                duk_pop(ctx);
 
14210
        }
 
14211
 
 
14212
        /*
 
14213
         *  Augment created errors upon creation (not when they are thrown or
 
14214
         *  rethrown).  __FILE__ and __LINE__ are not desirable here; the call
 
14215
         *  stack reflects the caller which is correct.
 
14216
         */
 
14217
 
 
14218
#ifdef DUK_USE_AUGMENT_ERROR_CREATE
 
14219
        duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
 
14220
#endif
 
14221
 
 
14222
        /* [... retval] */
 
14223
 
 
14224
        return;
 
14225
 
 
14226
 not_constructable:
 
14227
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not constructable");
 
14228
}
 
14229
 
 
14230
int duk_is_constructor_call(duk_context *ctx) {
 
14231
        duk_hthread *thr = (duk_hthread *) ctx;
 
14232
        duk_activation *act;
 
14233
 
 
14234
        DUK_ASSERT(ctx != NULL);
 
14235
        DUK_ASSERT(thr != NULL);
 
14236
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
 
14237
 
 
14238
        if (thr->callstack_top <= 0) {
 
14239
                return 0;
 
14240
        }
 
14241
 
 
14242
        act = thr->callstack + thr->callstack_top - 1;
 
14243
        return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
 
14244
}
 
14245
 
 
14246
int duk_is_strict_call(duk_context *ctx) {
 
14247
        duk_hthread *thr = (duk_hthread *) ctx;
 
14248
        duk_activation *act;
 
14249
 
 
14250
        DUK_ASSERT(ctx != NULL);
 
14251
        DUK_ASSERT(thr != NULL);
 
14252
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
 
14253
 
 
14254
        if (thr->callstack_top <= 0) {
 
14255
                return 0;
 
14256
        }
 
14257
 
 
14258
        act = thr->callstack + thr->callstack_top - 1;
 
14259
        return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
 
14260
}
 
14261
 
 
14262
/*
 
14263
 *  Duktape/C function magic
 
14264
 */
 
14265
 
 
14266
int duk_get_magic(duk_context *ctx) {
 
14267
        duk_hthread *thr = (duk_hthread *) ctx;
 
14268
        duk_activation *act;
 
14269
        duk_hobject *func;
 
14270
 
 
14271
        DUK_ASSERT(ctx != NULL);
 
14272
        DUK_ASSERT(thr != NULL);
 
14273
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
 
14274
 
 
14275
        if (thr->callstack_top <= 0) {
 
14276
                return 0;
 
14277
        }
 
14278
 
 
14279
        act = thr->callstack + thr->callstack_top - 1;
 
14280
        func = act->func;
 
14281
        DUK_ASSERT(func != NULL);
 
14282
 
 
14283
        if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
 
14284
                duk_hnativefunction *nf = (duk_hnativefunction *) func;
 
14285
                return (int) nf->magic;
 
14286
        }
 
14287
 
 
14288
        return 0;
 
14289
}
 
14290
 
 
14291
#line 1 "duk_api_codec.c"
 
14292
/*
 
14293
 *  Encoding and decoding basic formats: hex, base64.
 
14294
 *
 
14295
 *  These are in-place operations which may allow an optimized implementation.
 
14296
 */
 
14297
 
 
14298
/* include removed: duk_internal.h */
 
14299
 
 
14300
/* dst length must be exactly ceil(len/3)*4 */
 
14301
static void duk__base64_encode_helper(const unsigned char *src, const unsigned char *src_end,
 
14302
                                      unsigned char *dst, unsigned char *dst_end) {
 
14303
        unsigned int i, snip;
 
14304
        unsigned int x, y, t;
 
14305
 
 
14306
        DUK_UNREF(dst_end);
 
14307
 
 
14308
        while (src < src_end) {
 
14309
                /* read 3 bytes into 't', padded by zero */
 
14310
                snip = 4;
 
14311
                t = 0;
 
14312
                for (i = 0; i < 3; i++) {
 
14313
                        t = t << 8;
 
14314
                        if (src >= src_end) {
 
14315
                                snip--;
 
14316
                        } else {
 
14317
                                t += (unsigned int) (*src++);
 
14318
                        }
 
14319
                }
 
14320
 
 
14321
                /*
 
14322
                 *  Missing bytes    snip     base64 example
 
14323
                 *    0               4         XXXX
 
14324
                 *    1               3         XXX=
 
14325
                 *    2               2         XX==
 
14326
                 */
 
14327
 
 
14328
                DUK_ASSERT(snip >= 2 && snip <= 4);
 
14329
 
 
14330
                for (i = 0; i < 4; i++) {
 
14331
                        x = (t >> 18) & 0x3f;
 
14332
                        t = t << 6;
 
14333
 
 
14334
                        /* A straightforward 64-byte lookup would be faster
 
14335
                         * and cleaner, but this is shorter.
 
14336
                         */
 
14337
                        if (i >= snip) {
 
14338
                                y = '=';
 
14339
                        } else if (x <= 25) {
 
14340
                                y = x + 'A';
 
14341
                        } else if (x <= 51) {
 
14342
                                y = x - 26 + 'a';
 
14343
                        } else if (x <= 61) {
 
14344
                                y = x - 52 + '0';
 
14345
                        } else if (x == 62) {
 
14346
                                y = '+';
 
14347
                        } else {
 
14348
                                y = '/';
 
14349
                        }
 
14350
 
 
14351
                        DUK_ASSERT(dst < dst_end);
 
14352
                        *dst++ = (unsigned char) y;
 
14353
                }
 
14354
        }
 
14355
}
 
14356
 
 
14357
static int duk__base64_decode_helper(const unsigned char *src, const unsigned char *src_end,
 
14358
                                     unsigned char *dst, unsigned char *dst_end, unsigned char **out_dst_final) {
 
14359
        unsigned int t;
 
14360
        unsigned int x, y;
 
14361
        int group_idx;
 
14362
 
 
14363
        DUK_UNREF(dst_end);
 
14364
 
 
14365
        t = 0;
 
14366
        group_idx = 0;
 
14367
 
 
14368
        while (src < src_end) {
 
14369
                x = *src++;
 
14370
 
 
14371
                if (x >= 'A' && x <= 'Z') {
 
14372
                        y = x - 'A' + 0;
 
14373
                } else if (x >= 'a' && x <= 'z') {
 
14374
                        y = x - 'a' + 26;
 
14375
                } else if (x >= '0' && x <= '9') {
 
14376
                        y = x - '0' + 52;
 
14377
                } else if (x == '+') {
 
14378
                        y = 62;
 
14379
                } else if (x == '/') {
 
14380
                        y = 63;
 
14381
                } else if (x == '=') {
 
14382
                        /* We don't check the zero padding bytes here right now.
 
14383
                         * This seems to be common behavior for base-64 decoders.
 
14384
                         */
 
14385
 
 
14386
                        if (group_idx == 2) {
 
14387
                                /* xx== -> 1 byte, t contains 12 bits, 4 on right are zero */
 
14388
                                t = t >> 4;
 
14389
                                DUK_ASSERT(dst < dst_end);
 
14390
                                *dst++ = (unsigned char) t;
 
14391
 
 
14392
                                if (src >= src_end) {
 
14393
                                        goto error;
 
14394
                                }
 
14395
                                x = *src++;
 
14396
                                if (x != '=') {
 
14397
                                        goto error;
 
14398
                                }
 
14399
                        } else if (group_idx == 3) {
 
14400
                                /* xxx= -> 2 bytes, t contains 18 bits, 2 on right are zero */
 
14401
                                t = t >> 2;
 
14402
                                DUK_ASSERT(dst < dst_end);
 
14403
                                *dst++ = (unsigned char) ((t >> 8) & 0xff);
 
14404
                                DUK_ASSERT(dst < dst_end);
 
14405
                                *dst++ = (unsigned char) (t & 0xff);
 
14406
                        } else {
 
14407
                                goto error;
 
14408
                        }
 
14409
 
 
14410
                        /* Here we can choose either to end parsing and ignore
 
14411
                         * whatever follows, or to continue parsing in case
 
14412
                         * multiple (possibly padded) base64 strings have been
 
14413
                         * concatenated.  Currently, keep on parsing.
 
14414
                         */
 
14415
                        t = 0;
 
14416
                        group_idx = 0;
 
14417
                        continue;
 
14418
                } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
 
14419
                        /* allow basic ASCII whitespace */
 
14420
                        continue;
 
14421
                } else {
 
14422
                        goto error;
 
14423
                }
 
14424
 
 
14425
                t = (t << 6) + y;
 
14426
 
 
14427
                if (group_idx == 3) {
 
14428
                        /* output 3 bytes from 't' */
 
14429
                        DUK_ASSERT(dst < dst_end);
 
14430
                        *dst++ = (unsigned char) ((t >> 16) & 0xff);
 
14431
                        DUK_ASSERT(dst < dst_end);
 
14432
                        *dst++ = (unsigned char) ((t >> 8) & 0xff);
 
14433
                        DUK_ASSERT(dst < dst_end);
 
14434
                        *dst++ = (unsigned char) (t & 0xff);
 
14435
                        t = 0;
 
14436
                        group_idx = 0;
 
14437
                } else {
 
14438
                        group_idx++;
 
14439
                }
 
14440
        }
 
14441
 
 
14442
        if (group_idx != 0) {
 
14443
                /* Here we'd have the option of decoding unpadded base64
 
14444
                 * (e.g. "xxxxyy" instead of "xxxxyy==".  Currently not
 
14445
                 * accepted.
 
14446
                 */
 
14447
                goto error;
 
14448
        }
 
14449
 
 
14450
        *out_dst_final = dst;
 
14451
        return 1;
 
14452
 
 
14453
 error:
 
14454
        return 0;
 
14455
}
 
14456
 
 
14457
const char *duk_base64_encode(duk_context *ctx, int index) {
 
14458
        duk_hthread *thr = (duk_hthread *) ctx;
 
14459
        unsigned char *src;
 
14460
        size_t srclen;
 
14461
        size_t dstlen;
 
14462
        unsigned char *dst;
 
14463
        const char *ret;
 
14464
 
 
14465
        /* FIXME: optimize for string inputs: no need to coerce to a buffer
 
14466
         * which makes a copy of the input.
 
14467
         */
 
14468
 
 
14469
        index = duk_require_normalize_index(ctx, index);
 
14470
        src = (unsigned char *) duk_to_buffer(ctx, index, &srclen);
 
14471
        /* Note: for srclen=0, src may be NULL */
 
14472
 
 
14473
        /* Computation must not wrap; this limit works for 32-bit size_t:
 
14474
         * >>> srclen = 3221225469
 
14475
         * >>> '%x' % ((srclen + 2) / 3 * 4)
 
14476
         * 'fffffffc'
 
14477
         */
 
14478
        if (srclen > 3221225469U) {
 
14479
                goto type_error;
 
14480
        }
 
14481
        dstlen = (srclen + 2) / 3 * 4;
 
14482
        dst = (unsigned char *) duk_push_fixed_buffer(ctx, dstlen);
 
14483
 
 
14484
        duk__base64_encode_helper((const unsigned char *) src, (const unsigned char *) (src + srclen),
 
14485
                                  (unsigned char *) dst, (unsigned char *) (dst + dstlen));
 
14486
 
 
14487
        ret = duk_to_string(ctx, -1);
 
14488
        duk_replace(ctx, index);
 
14489
        return ret;
 
14490
 
 
14491
 type_error:
 
14492
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "base64 encode failed");
 
14493
        return NULL;  /* never here */
 
14494
}
 
14495
 
 
14496
void duk_base64_decode(duk_context *ctx, int index) {
 
14497
        duk_hthread *thr = (duk_hthread *) ctx;
 
14498
        const char *src;
 
14499
        size_t srclen;
 
14500
        size_t dstlen;
 
14501
        unsigned char *dst;
 
14502
        unsigned char *dst_final;
 
14503
        int retval;
 
14504
 
 
14505
        /* FIXME: optimize for buffer inputs: no need to coerce to a string
 
14506
         * which causes an unnecessary interning.
 
14507
         */
 
14508
 
 
14509
        index = duk_require_normalize_index(ctx, index);
 
14510
        src = duk_to_lstring(ctx, index, &srclen);
 
14511
 
 
14512
        /* Computation must not wrap, only srclen + 3 is at risk of
 
14513
         * wrapping because after that the number gets smaller.
 
14514
         * This limit works for 32-bit size_t:
 
14515
         * 0x100000000 - 3 - 1 = 4294967292
 
14516
         */
 
14517
        if (srclen > 4294967292U) {
 
14518
                goto type_error;
 
14519
        }
 
14520
        dstlen = (srclen + 3) / 4 * 3;  /* upper limit */
 
14521
        dst = (unsigned char *) duk_push_dynamic_buffer(ctx, dstlen);
 
14522
        /* Note: for dstlen=0, dst may be NULL */
 
14523
 
 
14524
        retval = duk__base64_decode_helper((unsigned char *) src, (unsigned char *) (src + srclen),
 
14525
                                           dst, dst + dstlen, &dst_final);
 
14526
        if (!retval) {
 
14527
                goto type_error;
 
14528
        }
 
14529
 
 
14530
        /* XXX: convert to fixed buffer? */
 
14531
        (void) duk_resize_buffer(ctx, -1, (size_t) (dst_final - dst));
 
14532
        duk_replace(ctx, index);
 
14533
        return;
 
14534
 
 
14535
 type_error:
 
14536
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "base64 decode failed");
 
14537
}
 
14538
 
 
14539
const char *duk_hex_encode(duk_context *ctx, int index) {
 
14540
        unsigned char *data;
 
14541
        size_t len;
 
14542
        size_t i;
 
14543
        int t;
 
14544
        unsigned char *buf;
 
14545
        const char *ret;
 
14546
 
 
14547
        /* FIXME: special case for input string, no need to coerce to buffer */
 
14548
 
 
14549
        index = duk_require_normalize_index(ctx, index);
 
14550
        data = (unsigned char *) duk_to_buffer(ctx, index, &len);
 
14551
        DUK_ASSERT(data != NULL);
 
14552
 
 
14553
        buf = (unsigned char *) duk_push_fixed_buffer(ctx, len * 2);
 
14554
        DUK_ASSERT(buf != NULL);
 
14555
        /* buf is always zeroed */
 
14556
 
 
14557
        for (i = 0; i < len; i++) {
 
14558
                t = data[i];
 
14559
                buf[i*2 + 0] = duk_lc_digits[t >> 4];
 
14560
                buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
 
14561
        }
 
14562
 
 
14563
        ret = duk_to_string(ctx, -1);
 
14564
        duk_replace(ctx, index);
 
14565
        return ret;
 
14566
}
 
14567
 
 
14568
void duk_hex_decode(duk_context *ctx, int index) {
 
14569
        duk_hthread *thr = (duk_hthread *) ctx;
 
14570
        const char *str;
 
14571
        size_t len;
 
14572
        size_t i;
 
14573
        int t;
 
14574
        unsigned char *buf;
 
14575
 
 
14576
        /* FIXME: optimize for buffer inputs: no need to coerce to a string
 
14577
         * which causes an unnecessary interning.
 
14578
         */
 
14579
 
 
14580
        index = duk_require_normalize_index(ctx, index);
 
14581
        str = duk_to_lstring(ctx, index, &len);
 
14582
        DUK_ASSERT(str != NULL);
 
14583
 
 
14584
        if (len & 0x01) {
 
14585
                goto type_error;
 
14586
        }
 
14587
 
 
14588
        buf = (unsigned char *) duk_push_fixed_buffer(ctx, len / 2);
 
14589
        DUK_ASSERT(buf != NULL);
 
14590
        /* buf is always zeroed */
 
14591
 
 
14592
        for (i = 0; i < len; i++) {
 
14593
                t = str[i];
 
14594
                if (t >= '0' && t <= '9') {
 
14595
                        t = t - '0' + 0x00;
 
14596
                } else if (t >= 'a' && t <= 'f') {
 
14597
                        t = t - 'a' + 0x0a;
 
14598
                } else if (t >= 'A' && t <= 'F') {
 
14599
                        t = t - 'A' + 0x0a;
 
14600
                } else {
 
14601
                        goto type_error;
 
14602
                }
 
14603
 
 
14604
                if (i & 0x01) {
 
14605
                        buf[i >> 1] += (unsigned char) t;
 
14606
                } else {
 
14607
                        buf[i >> 1] = (unsigned char) (t << 4);
 
14608
                }
 
14609
        }
 
14610
 
 
14611
        duk_replace(ctx, index);
 
14612
        return;
 
14613
 
 
14614
 type_error:
 
14615
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "hex decode failed");
 
14616
}
 
14617
 
 
14618
const char *duk_json_encode(duk_context *ctx, int index) {
 
14619
#ifdef DUK_USE_ASSERTIONS
 
14620
        int top_at_entry = duk_get_top(ctx);
 
14621
#endif
 
14622
        const char *ret;
 
14623
 
 
14624
        index = duk_require_normalize_index(ctx, index);
 
14625
        duk_bi_json_stringify_helper(ctx,
 
14626
                                     index /*idx_value*/,
 
14627
                                     DUK_INVALID_INDEX /*idx_replacer*/,
 
14628
                                     DUK_INVALID_INDEX /*idx_space*/,
 
14629
                                     0 /*flags*/);
 
14630
        DUK_ASSERT(duk_is_string(ctx, -1));
 
14631
        duk_replace(ctx, index);
 
14632
        ret = duk_get_string(ctx, index);
 
14633
 
 
14634
        DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
 
14635
 
 
14636
        return ret;
 
14637
}
 
14638
 
 
14639
void duk_json_decode(duk_context *ctx, int index) {
 
14640
#ifdef DUK_USE_ASSERTIONS
 
14641
        int top_at_entry = duk_get_top(ctx);
 
14642
#endif
 
14643
 
 
14644
        index = duk_require_normalize_index(ctx, index);
 
14645
        duk_bi_json_parse_helper(ctx,
 
14646
                                 index /*idx_value*/,
 
14647
                                 DUK_INVALID_INDEX /*idx_reviver*/,
 
14648
                                 0 /*flags*/);
 
14649
        duk_replace(ctx, index);
 
14650
 
 
14651
        DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
 
14652
}
 
14653
 
 
14654
#line 1 "duk_api_compile.c"
 
14655
/*
 
14656
 *  Compilation and evaluation
 
14657
 */
 
14658
 
 
14659
/* include removed: duk_internal.h */
 
14660
 
 
14661
/* Eval is just a wrapper now. */
 
14662
int duk_eval_raw(duk_context *ctx, int flags) {
 
14663
        int comp_flags;
 
14664
        int rc;
 
14665
 
 
14666
        /* [ ... source filename ] */
 
14667
 
 
14668
        comp_flags = flags;
 
14669
        comp_flags |= DUK_COMPILE_EVAL;
 
14670
        if (duk_is_strict_call(ctx)) {
 
14671
                comp_flags |= DUK_COMPILE_STRICT;
 
14672
        }
 
14673
        rc = duk_compile_raw(ctx, comp_flags);  /* may be safe, or non-safe depending on flags */
 
14674
 
 
14675
        /* [ ... closure/error ] */
 
14676
 
 
14677
        if (rc != DUK_EXEC_SUCCESS) {
 
14678
                rc = DUK_EXEC_ERROR;
 
14679
                goto got_rc;
 
14680
        }
 
14681
 
 
14682
        if (flags & DUK_COMPILE_SAFE) {
 
14683
                rc = duk_pcall(ctx, 0);
 
14684
        } else {
 
14685
                duk_call(ctx, 0);
 
14686
                rc = DUK_EXEC_SUCCESS;
 
14687
        }
 
14688
 
 
14689
        /* [ ... result/error ] */
 
14690
 
 
14691
 got_rc:
 
14692
        if (flags & DUK_COMPILE_NORESULT) {
 
14693
                duk_pop(ctx);
 
14694
        }
 
14695
 
 
14696
        return rc;
 
14697
}
 
14698
 
 
14699
/* Helper which can be called both directly and with duk_safe_call(). */
 
14700
static int duk__do_compile(duk_context *ctx) {
 
14701
        duk_hthread *thr = (duk_hthread *) ctx;
 
14702
        int flags;
 
14703
        int comp_flags;
 
14704
        duk_hcompiledfunction *h_templ;
 
14705
 
 
14706
        /* [ ... source filename flags ] */
 
14707
 
 
14708
        flags = duk_get_number(ctx, -1);
 
14709
        duk_pop(ctx);
 
14710
 
 
14711
        /* [ ... source filename ] */
 
14712
 
 
14713
        /* FIXME: unnecessary translation of flags */
 
14714
        comp_flags = 0;
 
14715
        if (flags & DUK_COMPILE_EVAL) {
 
14716
                comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
 
14717
        }
 
14718
        if (flags & DUK_COMPILE_FUNCTION) {
 
14719
                duk_error(ctx, DUK_ERR_UNIMPLEMENTED_ERROR, "unimplemented");
 
14720
        }
 
14721
        if (flags & DUK_COMPILE_STRICT) {
 
14722
                comp_flags = DUK_JS_COMPILE_FLAG_STRICT;
 
14723
        }
 
14724
 
 
14725
        duk_js_compile(thr, comp_flags);
 
14726
        h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
 
14727
 
 
14728
        /* [ ... func_template ] */
 
14729
 
 
14730
        duk_js_push_closure(thr,
 
14731
                           h_templ,
 
14732
                           thr->builtins[DUK_BIDX_GLOBAL_ENV],
 
14733
                           thr->builtins[DUK_BIDX_GLOBAL_ENV]);
 
14734
 
 
14735
        /* [ ... func_template closure ] */
 
14736
 
 
14737
        duk_remove(ctx, -2);  /* -> [ ... closure ] */
 
14738
 
 
14739
        /* [ ... closure ] */
 
14740
 
 
14741
        return 1;
 
14742
}
 
14743
 
 
14744
int duk_compile_raw(duk_context *ctx, int flags) {
 
14745
        duk_push_int(ctx, flags);
 
14746
 
 
14747
        if (flags & DUK_COMPILE_SAFE) {
 
14748
                int rc = duk_safe_call(ctx, duk__do_compile, 3 /*nargs*/, 1 /*nrets*/);
 
14749
                return rc;
 
14750
        }
 
14751
 
 
14752
        (void) duk__do_compile(ctx);
 
14753
        return DUK_EXEC_SUCCESS;
 
14754
}
 
14755
 
 
14756
#line 1 "duk_api_logging.c"
 
14757
/*
 
14758
 *  Logging
 
14759
 *
 
14760
 *  Current logging primitive is a sprintf-style log which is convenient
 
14761
 *  for most C code.  Another useful primitive would be to log N arguments
 
14762
 *  from value stack (like the Ecmascript binding does).
 
14763
 */
 
14764
 
 
14765
/* include removed: duk_internal.h */
 
14766
 
 
14767
/* FIXME: dynamic? shared code with sprintf string pusher? */
 
14768
#define DUK__LOGFMT_BUFSIZE  256  /* size for formatting buffers */
 
14769
 
 
14770
void duk_log(duk_context *ctx, int level, const char *fmt, ...) {
 
14771
        duk_hthread *thr = (duk_hthread *) ctx;
 
14772
        va_list ap;
 
14773
        char buf[DUK__LOGFMT_BUFSIZE];
 
14774
        duk_uint16_t stridx_logfunc[6] = {
 
14775
                DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
 
14776
                DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
 
14777
        };
 
14778
 
 
14779
        if (level < 0) {
 
14780
                level = 0;
 
14781
        } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
 
14782
                level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
 
14783
        }
 
14784
 
 
14785
        va_start(ap, fmt);
 
14786
        DUK_VSNPRINTF(buf, sizeof(buf), fmt, ap);
 
14787
        buf[sizeof(buf) - 1] = (char) 0;
 
14788
        va_end(ap);
 
14789
 
 
14790
        duk_push_hobject(ctx, thr->builtins[DUK_BIDX_LOGGER_CONSTRUCTOR]);
 
14791
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
 
14792
        duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
 
14793
 
 
14794
        /* [ ... Logger clog info ] */
 
14795
 
 
14796
        duk_dup(ctx, -2);
 
14797
        duk_push_string(ctx, buf);  /* FIXME: duk_push_vsprintf? */
 
14798
 
 
14799
        /* [ ... Logger clog info clog msg ] */
 
14800
 
 
14801
        duk_call_method(ctx, 1 /*nargs*/);
 
14802
 
 
14803
        /* [ ... Logger clog res ] */
 
14804
 
 
14805
        duk_pop_3(ctx);
 
14806
}
 
14807
 
 
14808
#line 1 "duk_api_memory.c"
 
14809
/*
 
14810
 *  Memory calls.
 
14811
 */
 
14812
 
 
14813
/* include removed: duk_internal.h */
 
14814
 
 
14815
void *duk_alloc_raw(duk_context *ctx, size_t size) {
 
14816
        duk_hthread *thr = (duk_hthread *) ctx;
 
14817
 
 
14818
        DUK_ASSERT(ctx != NULL);
 
14819
 
 
14820
        return DUK_ALLOC_RAW(thr->heap, size);
 
14821
}
 
14822
 
 
14823
void duk_free_raw(duk_context *ctx, void *ptr) {
 
14824
        duk_hthread *thr = (duk_hthread *) ctx;
 
14825
 
 
14826
        DUK_ASSERT(ctx != NULL);
 
14827
 
 
14828
        DUK_FREE_RAW(thr->heap, ptr);
 
14829
}
 
14830
 
 
14831
void *duk_realloc_raw(duk_context *ctx, void *ptr, size_t size) {
 
14832
        duk_hthread *thr = (duk_hthread *) ctx;
 
14833
 
 
14834
        DUK_ASSERT(ctx != NULL);
 
14835
 
 
14836
        return DUK_REALLOC_RAW(thr->heap, ptr, size);
 
14837
}
 
14838
 
 
14839
void *duk_alloc(duk_context *ctx, size_t size) {
 
14840
        duk_hthread *thr = (duk_hthread *) ctx;
 
14841
 
 
14842
        DUK_ASSERT(ctx != NULL);
 
14843
 
 
14844
        return DUK_ALLOC(thr->heap, size);
 
14845
}
 
14846
 
 
14847
void duk_free(duk_context *ctx, void *ptr) {
 
14848
        duk_hthread *thr = (duk_hthread *) ctx;
 
14849
 
 
14850
        DUK_ASSERT(ctx != NULL);
 
14851
 
 
14852
        DUK_FREE(thr->heap, ptr);
 
14853
}
 
14854
 
 
14855
void *duk_realloc(duk_context *ctx, void *ptr, size_t size) {
 
14856
        duk_hthread *thr = (duk_hthread *) ctx;
 
14857
 
 
14858
        DUK_ASSERT(ctx != NULL);
 
14859
 
 
14860
        /*
 
14861
         *  Note: since this is an exposed API call, there should be
 
14862
         *  no way a mark-and-sweep could have a side effect on the
 
14863
         *  memory allocation behind 'ptr'; the pointer should never
 
14864
         *  be something that Duktape wants to change.
 
14865
         *
 
14866
         *  Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
 
14867
         *  have the storage location here anyway).
 
14868
         */
 
14869
 
 
14870
        return DUK_REALLOC(thr->heap, ptr, size);
 
14871
}
 
14872
 
 
14873
void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
 
14874
        duk_hthread *thr = (duk_hthread *) ctx;
 
14875
        duk_heap *heap;
 
14876
 
 
14877
        DUK_ASSERT(ctx != NULL);
 
14878
        DUK_ASSERT(out_funcs != NULL);
 
14879
        DUK_ASSERT(thr != NULL);
 
14880
        DUK_ASSERT(thr->heap != NULL);
 
14881
 
 
14882
        heap = thr->heap;
 
14883
        out_funcs->alloc = heap->alloc_func;
 
14884
        out_funcs->realloc = heap->realloc_func;
 
14885
        out_funcs->free = heap->free_func;
 
14886
        out_funcs->udata = heap->alloc_udata;
 
14887
}
 
14888
 
 
14889
void duk_gc(duk_context *ctx, int flags) {
 
14890
#ifdef DUK_USE_MARK_AND_SWEEP
 
14891
        duk_hthread *thr = (duk_hthread *) ctx;
 
14892
        duk_heap *heap;
 
14893
 
 
14894
        DUK_UNREF(flags);
 
14895
 
 
14896
        if (!ctx) {
 
14897
                return;
 
14898
        }
 
14899
        heap = thr->heap;
 
14900
        DUK_ASSERT(heap != NULL);
 
14901
 
 
14902
        DUK_DPRINT("mark-and-sweep requested by application");
 
14903
        duk_heap_mark_and_sweep(heap, 0);
 
14904
#else
 
14905
        DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring");
 
14906
        DUK_UNREF(ctx);
 
14907
        DUK_UNREF(flags);
 
14908
#endif
 
14909
}
 
14910
 
 
14911
#line 1 "duk_api_object.c"
 
14912
/*
 
14913
 *  Object handling: property access and other support functions.
 
14914
 */
 
14915
 
 
14916
/* include removed: duk_internal.h */
 
14917
 
 
14918
/*
 
14919
 *  Property handling
 
14920
 *
 
14921
 *  The API exposes only the most common property handling functions.
 
14922
 *  The caller can invoke Ecmascript built-ins for full control (e.g.
 
14923
 *  defineProperty, getOwnPropertyDescriptor).
 
14924
 */
 
14925
 
 
14926
int duk_get_prop(duk_context *ctx, int obj_index) {
 
14927
        duk_hthread *thr = (duk_hthread *) ctx;
 
14928
        duk_tval *tv_obj;
 
14929
        duk_tval *tv_key;
 
14930
        int rc;
 
14931
 
 
14932
        DUK_ASSERT(ctx != NULL);
 
14933
 
 
14934
        /* Note: copying tv_obj and tv_key to locals to shield against a valstack
 
14935
         * resize is not necessary for a property get right now.
 
14936
         */
 
14937
 
 
14938
        tv_obj = duk_require_tval(ctx, obj_index);
 
14939
        tv_key = duk_require_tval(ctx, -1);
 
14940
 
 
14941
        rc = duk_hobject_getprop(thr, tv_obj, tv_key);
 
14942
        /* a value is left on stack regardless of rc */
 
14943
 
 
14944
        duk_remove(ctx, -2);  /* remove key */
 
14945
        return rc;  /* 1 if property found, 0 otherwise */
 
14946
}
 
14947
 
 
14948
int duk_get_prop_string(duk_context *ctx, int obj_index, const char *key) {
 
14949
        DUK_ASSERT(ctx != NULL);
 
14950
        DUK_ASSERT(key != NULL);
 
14951
 
 
14952
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
14953
        duk_push_string(ctx, key);
 
14954
        return duk_get_prop(ctx, obj_index);
 
14955
}
 
14956
 
 
14957
int duk_get_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index) {
 
14958
        DUK_ASSERT(ctx != NULL);
 
14959
 
 
14960
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
14961
        duk_push_number(ctx, (double) arr_index);
 
14962
        return duk_get_prop(ctx, obj_index);
 
14963
}
 
14964
 
 
14965
int duk_get_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx) {
 
14966
        duk_hthread *thr = (duk_hthread *) ctx;
 
14967
 
 
14968
        DUK_ASSERT(ctx != NULL);
 
14969
        DUK_ASSERT_DISABLE(stridx >= 0);
 
14970
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
14971
 
 
14972
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
14973
        duk_push_hstring(ctx, thr->strs[stridx]);
 
14974
        return duk_get_prop(ctx, obj_index);
 
14975
}
 
14976
 
 
14977
int duk_get_prop_stridx_boolean(duk_context *ctx, int obj_index, duk_small_int_t stridx, int *out_has_prop) {
 
14978
        int rc;
 
14979
 
 
14980
        DUK_ASSERT(ctx != NULL);
 
14981
        DUK_ASSERT_DISABLE(stridx >= 0);
 
14982
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
14983
 
 
14984
        rc = duk_get_prop_stridx(ctx, obj_index, stridx);
 
14985
        if (out_has_prop) {
 
14986
                *out_has_prop = rc;
 
14987
        }
 
14988
        rc = duk_to_boolean(ctx, -1);
 
14989
        duk_pop(ctx);
 
14990
        return rc;
 
14991
}
 
14992
 
 
14993
int duk_put_prop(duk_context *ctx, int obj_index) {
 
14994
        duk_hthread *thr = (duk_hthread *) ctx;
 
14995
        duk_tval *tv_obj;
 
14996
        duk_tval *tv_key;
 
14997
        duk_tval *tv_val;
 
14998
        int throw_flag;
 
14999
        int rc;
 
15000
 
 
15001
        DUK_ASSERT(ctx != NULL);
 
15002
 
 
15003
        /* Note: copying tv_obj and tv_key to locals to shield against a valstack
 
15004
         * resize is not necessary for a property put right now (putprop protects
 
15005
         * against it internally).
 
15006
         */
 
15007
 
 
15008
        tv_obj = duk_require_tval(ctx, obj_index);
 
15009
        tv_key = duk_require_tval(ctx, -2);
 
15010
        tv_val = duk_require_tval(ctx, -1);
 
15011
        throw_flag = duk_is_strict_call(ctx);  /* FIXME */
 
15012
 
 
15013
        rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
 
15014
 
 
15015
        duk_pop_2(ctx);  /* remove key and value */
 
15016
        return rc;  /* 1 if property found, 0 otherwise */
 
15017
}
 
15018
 
 
15019
int duk_put_prop_string(duk_context *ctx, int obj_index, const char *key) {
 
15020
        DUK_ASSERT(ctx != NULL);
 
15021
        DUK_ASSERT(key != NULL);
 
15022
 
 
15023
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15024
        duk_push_string(ctx, key);
 
15025
        duk_swap_top(ctx, -2);  /* [val key] -> [key val] */
 
15026
        return duk_put_prop(ctx, obj_index);
 
15027
}
 
15028
 
 
15029
int duk_put_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index) {
 
15030
        DUK_ASSERT(ctx != NULL);
 
15031
 
 
15032
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15033
        duk_push_number(ctx, (double) arr_index);
 
15034
        duk_swap_top(ctx, -2);  /* [val key] -> [key val] */
 
15035
        return duk_put_prop(ctx, obj_index);
 
15036
}
 
15037
 
 
15038
int duk_put_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx) {
 
15039
        duk_hthread *thr = (duk_hthread *) ctx;
 
15040
 
 
15041
        DUK_ASSERT(ctx != NULL);
 
15042
        DUK_ASSERT_DISABLE(stridx >= 0);
 
15043
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
15044
 
 
15045
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15046
        duk_push_hstring(ctx, thr->strs[stridx]);
 
15047
        duk_swap_top(ctx, -2);  /* [val key] -> [key val] */
 
15048
        return duk_put_prop(ctx, obj_index);
 
15049
}
 
15050
 
 
15051
int duk_del_prop(duk_context *ctx, int obj_index) {
 
15052
        duk_hthread *thr = (duk_hthread *) ctx;
 
15053
        duk_tval *tv_obj;
 
15054
        duk_tval *tv_key;
 
15055
        int throw_flag;
 
15056
        int rc;
 
15057
 
 
15058
        DUK_ASSERT(ctx != NULL);
 
15059
 
 
15060
        /* Note: copying tv_obj and tv_key to locals to shield against a valstack
 
15061
         * resize is not necessary for a property delete right now.
 
15062
         */
 
15063
 
 
15064
        tv_obj = duk_require_tval(ctx, obj_index);
 
15065
        tv_key = duk_require_tval(ctx, -1);
 
15066
        throw_flag = duk_is_strict_call(ctx);  /* FIXME */
 
15067
 
 
15068
        rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
 
15069
 
 
15070
        duk_pop(ctx);  /* remove key */
 
15071
        return rc;
 
15072
}
 
15073
 
 
15074
int duk_del_prop_string(duk_context *ctx, int obj_index, const char *key) {
 
15075
        DUK_ASSERT(ctx != NULL);
 
15076
        DUK_ASSERT(key != NULL);
 
15077
 
 
15078
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15079
        duk_push_string(ctx, key);
 
15080
        return duk_del_prop(ctx, obj_index);
 
15081
}
 
15082
 
 
15083
int duk_del_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index) {
 
15084
        DUK_ASSERT(ctx != NULL);
 
15085
 
 
15086
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15087
        duk_push_number(ctx, (double) arr_index);
 
15088
        return duk_del_prop(ctx, obj_index);
 
15089
}
 
15090
 
 
15091
int duk_del_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx) {
 
15092
        duk_hthread *thr = (duk_hthread *) ctx;
 
15093
 
 
15094
        DUK_ASSERT(ctx != NULL);
 
15095
        DUK_ASSERT_DISABLE(stridx >= 0);
 
15096
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
15097
 
 
15098
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15099
        duk_push_hstring(ctx, thr->strs[stridx]);
 
15100
        return duk_del_prop(ctx, obj_index);
 
15101
}
 
15102
 
 
15103
int duk_has_prop(duk_context *ctx, int obj_index) {
 
15104
        duk_hthread *thr = (duk_hthread *) ctx;
 
15105
        duk_tval *tv_obj;
 
15106
        duk_tval *tv_key;
 
15107
        int rc;
 
15108
 
 
15109
        DUK_ASSERT(ctx != NULL);
 
15110
 
 
15111
        /* Note: copying tv_obj and tv_key to locals to shield against a valstack
 
15112
         * resize is not necessary for a property existence check right now.
 
15113
         */
 
15114
 
 
15115
        tv_obj = duk_require_tval(ctx, obj_index);
 
15116
        tv_key = duk_require_tval(ctx, -1);
 
15117
 
 
15118
        rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
 
15119
 
 
15120
        duk_pop(ctx);  /* remove key */
 
15121
        return rc;  /* 1 if property found, 0 otherwise */
 
15122
}
 
15123
 
 
15124
int duk_has_prop_string(duk_context *ctx, int obj_index, const char *key) {
 
15125
        DUK_ASSERT(ctx != NULL);
 
15126
        DUK_ASSERT(key != NULL);
 
15127
 
 
15128
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15129
        duk_push_string(ctx, key);
 
15130
        return duk_has_prop(ctx, obj_index);
 
15131
}
 
15132
 
 
15133
int duk_has_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index) {
 
15134
        DUK_ASSERT(ctx != NULL);
 
15135
 
 
15136
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15137
        duk_push_number(ctx, (double) arr_index);
 
15138
        return duk_has_prop(ctx, obj_index);
 
15139
}
 
15140
 
 
15141
int duk_has_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx) {
 
15142
        duk_hthread *thr = (duk_hthread *) ctx;
 
15143
 
 
15144
        DUK_ASSERT(ctx != NULL);
 
15145
        DUK_ASSERT_DISABLE(stridx >= 0);
 
15146
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
15147
 
 
15148
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15149
        duk_push_hstring(ctx, thr->strs[stridx]);
 
15150
        return duk_has_prop(ctx, obj_index);
 
15151
}
 
15152
 
 
15153
/* Define own property without inheritance looks and such.  This differs from
 
15154
 * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
 
15155
 * not invoked by this method.  The caller must be careful to invoke any such
 
15156
 * behaviors if necessary.
 
15157
 */
 
15158
void duk_def_prop(duk_context *ctx, int obj_index, int desc_flags) {
 
15159
        duk_hthread *thr = (duk_hthread *) ctx;
 
15160
        duk_hobject *obj;
 
15161
        duk_hstring *key;
 
15162
 
 
15163
        DUK_ASSERT(ctx != NULL);
 
15164
 
 
15165
        obj = duk_require_hobject(ctx, obj_index);
 
15166
        DUK_ASSERT(obj != NULL);
 
15167
        key = duk_to_hstring(ctx, -2);
 
15168
        DUK_ASSERT(key != NULL);
 
15169
        DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
 
15170
 
 
15171
        duk_hobject_define_property_internal(thr, obj, key, desc_flags);
 
15172
 
 
15173
        duk_pop(ctx);  /* pop key */
 
15174
}
 
15175
 
 
15176
void duk_def_prop_index(duk_context *ctx, int obj_index, unsigned int arr_index, int desc_flags) {
 
15177
        duk_hthread *thr = (duk_hthread *) ctx;
 
15178
        duk_hobject *obj;
 
15179
 
 
15180
        DUK_ASSERT(ctx != NULL);
 
15181
 
 
15182
        obj = duk_require_hobject(ctx, obj_index);
 
15183
        DUK_ASSERT(obj != NULL);
 
15184
 
 
15185
        duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
 
15186
        /* value popped by call */
 
15187
}
 
15188
 
 
15189
void duk_def_prop_stridx(duk_context *ctx, int obj_index, unsigned int stridx, int desc_flags) {
 
15190
        duk_hthread *thr = (duk_hthread *) ctx;
 
15191
        duk_hobject *obj;
 
15192
        duk_hstring *key;
 
15193
 
 
15194
        DUK_ASSERT(ctx != NULL);
 
15195
        DUK_ASSERT_DISABLE(stridx >= 0);
 
15196
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
15197
 
 
15198
        obj = duk_require_hobject(ctx, obj_index);
 
15199
        DUK_ASSERT(obj != NULL);
 
15200
        key = thr->strs[stridx];
 
15201
        DUK_ASSERT(key != NULL);
 
15202
        DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
 
15203
 
 
15204
        duk_hobject_define_property_internal(thr, obj, key, desc_flags);
 
15205
        /* value popped by call */
 
15206
}
 
15207
 
 
15208
void duk_def_prop_stridx_builtin(duk_context *ctx, int obj_index, unsigned int stridx, unsigned int builtin_idx, int desc_flags) {
 
15209
        duk_hthread *thr = (duk_hthread *) ctx;
 
15210
        duk_hobject *obj;
 
15211
        duk_hstring *key;
 
15212
 
 
15213
        DUK_ASSERT(ctx != NULL);
 
15214
        DUK_ASSERT_DISABLE(stridx >= 0);
 
15215
        DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
 
15216
        DUK_ASSERT_DISABLE(builtin_idx >= 0);
 
15217
        DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
 
15218
 
 
15219
        obj = duk_require_hobject(ctx, obj_index);
 
15220
        DUK_ASSERT(obj != NULL);
 
15221
        key = thr->strs[stridx];
 
15222
        DUK_ASSERT(key != NULL);
 
15223
 
 
15224
        duk_push_hobject(ctx, thr->builtins[builtin_idx]);
 
15225
        duk_hobject_define_property_internal(thr, obj, key, desc_flags);
 
15226
        /* value popped by call */
 
15227
}
 
15228
 
 
15229
/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
 
15230
 * setter/getter into an object property.  This is needed by the 'arguments'
 
15231
 * object creation code, function instance creation code, and Function.prototype.bind().
 
15232
 */
 
15233
 
 
15234
void duk_def_prop_stridx_thrower(duk_context *ctx, int obj_index, unsigned int stridx, int desc_flags) {
 
15235
        duk_hthread *thr = (duk_hthread *) ctx;
 
15236
        duk_hobject *obj = duk_require_hobject(ctx, obj_index);
 
15237
        duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
 
15238
        duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
 
15239
}
 
15240
 
 
15241
/*
 
15242
 *  Object related
 
15243
 *
 
15244
 *  Note: seal() and freeze() are accessible through Ecmascript bindings,
 
15245
 *  and are not exposed through the API.
 
15246
 */
 
15247
 
 
15248
void duk_compact(duk_context *ctx, int obj_index) {
 
15249
        duk_hthread *thr = (duk_hthread *) ctx;
 
15250
        duk_hobject *obj;
 
15251
 
 
15252
        DUK_ASSERT(ctx != NULL);
 
15253
 
 
15254
        obj = duk_get_hobject(ctx, obj_index);
 
15255
        if (obj) {
 
15256
                /* Note: this may fail, caller should protect the call if necessary */
 
15257
                duk_hobject_compact_props(thr, obj);
 
15258
        }
 
15259
}
 
15260
 
 
15261
/* FIXME: the duk_hobject_enum.c stack APIs should be reworked */
 
15262
 
 
15263
void duk_enum(duk_context *ctx, int obj_index, int enum_flags) {
 
15264
        DUK_ASSERT(ctx != NULL);
 
15265
 
 
15266
        duk_require_hobject(ctx, obj_index);
 
15267
        duk_dup(ctx, obj_index);
 
15268
        duk_hobject_enumerator_create(ctx, enum_flags);   /* [target] -> [enum] */
 
15269
}
 
15270
 
 
15271
int duk_next(duk_context *ctx, int enum_index, int get_value) {
 
15272
        duk_require_hobject(ctx, enum_index);
 
15273
        duk_dup(ctx, enum_index);
 
15274
        return duk_hobject_enumerator_next(ctx, get_value);
 
15275
}
 
15276
 
 
15277
/*
 
15278
 *  Helpers for writing multiple properties
 
15279
 */
 
15280
 
 
15281
void duk_put_function_list(duk_context *ctx, int obj_index, const duk_function_list_entry *funcs) {
 
15282
        const duk_function_list_entry *ent = funcs;
 
15283
 
 
15284
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15285
        if (ent != NULL) {
 
15286
                while (ent->key != NULL) {
 
15287
                        duk_push_c_function(ctx, ent->value, ent->nargs);
 
15288
                        duk_put_prop_string(ctx, obj_index, ent->key);
 
15289
                        ent++;
 
15290
                }
 
15291
        }
 
15292
}
 
15293
 
 
15294
void duk_put_number_list(duk_context *ctx, int obj_index, const duk_number_list_entry *numbers) {
 
15295
        const duk_number_list_entry *ent = numbers;
 
15296
 
 
15297
        obj_index = duk_require_normalize_index(ctx, obj_index);
 
15298
        if (ent != NULL) {
 
15299
                while (ent->key != NULL) {
 
15300
                        duk_push_number(ctx, ent->value);
 
15301
                        duk_put_prop_string(ctx, obj_index, ent->key);
 
15302
                        ent++;
 
15303
                }
 
15304
        }
 
15305
}
 
15306
#line 1 "duk_api_string.c"
 
15307
/*
 
15308
 *  String manipulation
 
15309
 */
 
15310
 
 
15311
/* include removed: duk_internal.h */
 
15312
 
 
15313
static void duk__concat_and_join_helper(duk_context *ctx, unsigned int count, int is_join) {
 
15314
        duk_hthread *thr = (duk_hthread *) ctx;
 
15315
        unsigned int i;
 
15316
        unsigned int idx;
 
15317
        size_t len;
 
15318
        duk_hstring *h;
 
15319
        duk_uint8_t *buf;
 
15320
 
 
15321
        DUK_ASSERT(ctx != NULL);
 
15322
 
 
15323
        if (count <= 0) {
 
15324
                duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
15325
                return;
 
15326
        }
 
15327
 
 
15328
        if (is_join) {
 
15329
                size_t t1, t2, limit;
 
15330
                h = duk_to_hstring(ctx, -count-1);
 
15331
                DUK_ASSERT(h != NULL);
 
15332
 
 
15333
                /* A bit tricky overflow test, see doc/code-issues.txt. */
 
15334
                t1 = (size_t) DUK_HSTRING_GET_BYTELEN(h);
 
15335
                t2 = (size_t) (count - 1);
 
15336
                limit = (size_t) DUK_HSTRING_MAX_BYTELEN;
 
15337
                if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
 
15338
                        /* Combined size of separators already overflows */
 
15339
                        goto error_overflow;
 
15340
                }
 
15341
                len = (size_t) (t1 * t2);
 
15342
        } else {
 
15343
                len = (size_t) 0;
 
15344
        }
 
15345
 
 
15346
        for (i = count; i >= 1; i--) {
 
15347
                size_t new_len;
 
15348
                duk_to_string(ctx, -i);
 
15349
                h = duk_require_hstring(ctx, -i);
 
15350
                new_len = len + (size_t) DUK_HSTRING_GET_BYTELEN(h);
 
15351
 
 
15352
                /* Impose a string maximum length, need to handle overflow
 
15353
                 * correctly.
 
15354
                 */
 
15355
                if (new_len < len ||  /* wrapped */
 
15356
                    new_len > (size_t) DUK_HSTRING_MAX_BYTELEN) {
 
15357
                        goto error_overflow;
 
15358
                }
 
15359
                len = new_len;
 
15360
        }
 
15361
 
 
15362
        DUK_DDDPRINT("join/concat %d strings, total length %d bytes", (int) count, (int) len);
 
15363
 
 
15364
        /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
 
15365
        buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
 
15366
        DUK_ASSERT(buf != NULL);
 
15367
 
 
15368
        /* [... (sep) str1 str2 ... strN buf] */
 
15369
 
 
15370
        idx = 0;
 
15371
        for (i = count; i >= 1; i--) {
 
15372
                if (is_join && i != count) {
 
15373
                        h = duk_require_hstring(ctx, -count-2);  /* extra -1 for buffer */
 
15374
                        DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
 
15375
                        idx += DUK_HSTRING_GET_BYTELEN(h);
 
15376
                }
 
15377
                h = duk_require_hstring(ctx, -i-1);  /* extra -1 for buffer */
 
15378
                DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
 
15379
                idx += DUK_HSTRING_GET_BYTELEN(h);
 
15380
        }
 
15381
 
 
15382
        DUK_ASSERT(idx == len);
 
15383
 
 
15384
        /* [... (sep) str1 str2 ... strN buf] */
 
15385
 
 
15386
        /* get rid of the strings early to minimize memory use before intern */
 
15387
 
 
15388
        if (is_join) {
 
15389
                duk_replace(ctx, -count-2);  /* overwrite sep */
 
15390
                duk_pop_n(ctx, count);
 
15391
        } else {
 
15392
                duk_replace(ctx, -count-1);  /* overwrite str1 */
 
15393
                duk_pop_n(ctx, count-1);
 
15394
        }
 
15395
 
 
15396
        /* [... buf] */
 
15397
 
 
15398
        (void) duk_to_string(ctx, -1);
 
15399
 
 
15400
        /* [... res] */
 
15401
        return;
 
15402
 
 
15403
 error_overflow:
 
15404
        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "concat result too long");
 
15405
}
 
15406
 
 
15407
void duk_concat(duk_context *ctx, unsigned int count) {
 
15408
        duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
 
15409
}
 
15410
 
 
15411
void duk_join(duk_context *ctx, unsigned int count) {
 
15412
        duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
 
15413
}
 
15414
 
 
15415
/* FIXME: could map/decode be unified with duk_unicode_support.c code?
 
15416
 * Case conversion needs also the character surroundings though.
 
15417
 */
 
15418
 
 
15419
void duk_decode_string(duk_context *ctx, int index, duk_decode_char_function callback, void *udata) {
 
15420
        duk_hthread *thr = (duk_hthread *) ctx;
 
15421
        duk_hstring *h_input;
 
15422
        duk_uint8_t *p, *p_start, *p_end;
 
15423
        duk_codepoint_t cp;
 
15424
 
 
15425
        h_input = duk_require_hstring(ctx, index);
 
15426
        DUK_ASSERT(h_input != NULL);
 
15427
 
 
15428
        p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
 
15429
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
 
15430
        p = p_start;
 
15431
 
 
15432
        for (;;) {
 
15433
                if (p >= p_end) {
 
15434
                        break;
 
15435
                }
 
15436
                cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
 
15437
                callback(udata, cp);
 
15438
        }
 
15439
}
 
15440
 
 
15441
void duk_map_string(duk_context *ctx, int index, duk_map_char_function callback, void *udata) {
 
15442
        duk_hthread *thr = (duk_hthread *) ctx;
 
15443
        duk_hstring *h_input;
 
15444
        duk_hbuffer_dynamic *h_buf;
 
15445
        duk_uint8_t *p, *p_start, *p_end;
 
15446
        duk_codepoint_t cp;
 
15447
 
 
15448
        index = duk_normalize_index(ctx, index);
 
15449
 
 
15450
        h_input = duk_require_hstring(ctx, index);
 
15451
        DUK_ASSERT(h_input != NULL);
 
15452
 
 
15453
        /* FIXME: should init with a spare of at least h_input->blen? */
 
15454
        duk_push_dynamic_buffer(ctx, 0);
 
15455
        h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
15456
        DUK_ASSERT(h_buf != NULL);
 
15457
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf));
 
15458
 
 
15459
        p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
 
15460
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
 
15461
        p = p_start;
 
15462
 
 
15463
        for (;;) {
 
15464
                if (p >= p_end) {
 
15465
                        break;
 
15466
                }
 
15467
                cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
 
15468
                cp = callback(udata, cp);
 
15469
                duk_hbuffer_append_xutf8(thr, h_buf, cp);
 
15470
        }
 
15471
 
 
15472
        duk_to_string(ctx, -1);  /* invalidates h_buf pointer */
 
15473
        duk_replace(ctx, index);
 
15474
}
 
15475
 
 
15476
void duk_substring(duk_context *ctx, int index, size_t start_offset, size_t end_offset) {
 
15477
        duk_hthread *thr = (duk_hthread *) ctx;
 
15478
        duk_hstring *h;
 
15479
        duk_hstring *res;
 
15480
        size_t start_byte_offset;
 
15481
        size_t end_byte_offset;
 
15482
 
 
15483
        DUK_ASSERT(ctx != NULL);
 
15484
 
 
15485
        index = duk_require_normalize_index(ctx, index);
 
15486
        h = duk_require_hstring(ctx, index);
 
15487
        DUK_ASSERT(h != NULL);
 
15488
 
 
15489
        if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
 
15490
                end_offset = DUK_HSTRING_GET_CHARLEN(h);
 
15491
        }
 
15492
        if (start_offset > end_offset) {
 
15493
                start_offset = end_offset;
 
15494
        }
 
15495
 
 
15496
        DUK_ASSERT_DISABLE(start_offset >= 0);
 
15497
        DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
 
15498
        DUK_ASSERT_DISABLE(end_offset >= 0);
 
15499
        DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
 
15500
 
 
15501
        start_byte_offset = (size_t) duk_heap_strcache_offset_char2byte(thr, h, start_offset);
 
15502
        end_byte_offset = (size_t) duk_heap_strcache_offset_char2byte(thr, h, end_offset);
 
15503
 
 
15504
        DUK_ASSERT(end_byte_offset >= start_byte_offset);
 
15505
 
 
15506
        /* no size check is necessary */
 
15507
        res = duk_heap_string_intern_checked(thr,
 
15508
                                             DUK_HSTRING_GET_DATA(h) + start_byte_offset,
 
15509
                                             end_byte_offset - start_byte_offset);
 
15510
 
 
15511
        duk_push_hstring(ctx, res);
 
15512
        duk_replace(ctx, index);
 
15513
}
 
15514
 
 
15515
/* FIXME: this is quite clunky.  Add Unicode helpers to scan backwards and
 
15516
 * forwards with a callback to process codepoints?
 
15517
 */
 
15518
void duk_trim(duk_context *ctx, int index) {
 
15519
        duk_hthread *thr = (duk_hthread *) ctx;
 
15520
        duk_hstring *h;
 
15521
        duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2;  /* pointers for scanning */
 
15522
        duk_uint8_t *q_start, *q_end;  /* start (incl) and end (excl) of trimmed part */
 
15523
        duk_codepoint_t cp;
 
15524
 
 
15525
        index = duk_require_normalize_index(ctx, index);
 
15526
        h = duk_require_hstring(ctx, index);
 
15527
        DUK_ASSERT(h != NULL);
 
15528
 
 
15529
        p_start = DUK_HSTRING_GET_DATA(h);
 
15530
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
 
15531
 
 
15532
        p = p_start;
 
15533
        while (p < p_end) {
 
15534
                p_tmp1 = p;
 
15535
                cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
 
15536
                if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
 
15537
                        break;
 
15538
                }
 
15539
                p = p_tmp1;
 
15540
        }
 
15541
        q_start = p;
 
15542
        if (p == p_end) {
 
15543
                /* entire string is whitespace */
 
15544
                q_end = p;
 
15545
                goto scan_done;
 
15546
        }
 
15547
 
 
15548
        p = p_end;
 
15549
        while (p > p_start) {
 
15550
                p_tmp1 = p;
 
15551
                while (p > p_start) {
 
15552
                        p--;
 
15553
                        if (((*p) & 0xc0) != 0x80) {
 
15554
                                break;
 
15555
                        }
 
15556
                }
 
15557
                p_tmp2 = p;
 
15558
 
 
15559
                cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
 
15560
                if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
 
15561
                        p = p_tmp1;
 
15562
                        break;
 
15563
                }
 
15564
        }
 
15565
        q_end = p;
 
15566
 
 
15567
 scan_done:
 
15568
        /* This may happen when forward and backward scanning disagree.
 
15569
         * This may happen for non-extended-UTF-8 strings.
 
15570
         */
 
15571
        if (q_end < q_start) {
 
15572
                q_end = q_start;
 
15573
        }
 
15574
 
 
15575
        DUK_ASSERT(q_start >= p_start && q_start <= p_end);
 
15576
        DUK_ASSERT(q_end >= p_start && q_end <= p_end);
 
15577
        DUK_ASSERT(q_end >= q_start);
 
15578
 
 
15579
        DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
 
15580
                     (void *) p_start, (void *) p_end, (void *) q_start, (void *) q_end);
 
15581
 
 
15582
        if (q_start == p_start && q_end == p_end) {
 
15583
                DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)");
 
15584
                return;
 
15585
        }
 
15586
 
 
15587
        duk_push_lstring(ctx, (const char *) q_start, (size_t) (q_end - q_start));
 
15588
        duk_replace(ctx, index);
 
15589
}
 
15590
 
 
15591
int duk_char_code_at(duk_context *ctx, int index, duk_size_t char_offset) {
 
15592
        duk_hthread *thr = (duk_hthread *) ctx;
 
15593
        duk_hstring *h;
 
15594
        duk_ucodepoint_t cp;
 
15595
 
 
15596
        h = duk_require_hstring(ctx, index);
 
15597
        DUK_ASSERT(h != NULL);
 
15598
 
 
15599
        DUK_ASSERT_DISABLE(char_offset >= 0);  /* always true, arg is unsigned */
 
15600
        if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
 
15601
                return 0;
 
15602
        }
 
15603
 
 
15604
        cp = duk_hstring_char_code_at_raw(thr, h, char_offset);
 
15605
        return (int) cp;
 
15606
}
 
15607
#line 1 "duk_api_thread.c"
 
15608
/*
 
15609
 *  Thread handling
 
15610
 */
 
15611
 
 
15612
/* include removed: duk_internal.h */
 
15613
 
 
15614
/* FIXME */
 
15615
 
 
15616
#line 1 "duk_api_var.c"
 
15617
/*
 
15618
 *  Variable access
 
15619
 */
 
15620
 
 
15621
/* include removed: duk_internal.h */
 
15622
 
 
15623
void duk_get_var(duk_context *ctx) {
 
15624
        duk_hthread *thr = (duk_hthread *) ctx;
 
15625
        duk_activation *act;
 
15626
        duk_hstring *h_varname;
 
15627
        duk_small_int_t throw_flag = 1;  /* always throw ReferenceError for unresolvable */
 
15628
 
 
15629
        DUK_ASSERT(ctx != NULL);
 
15630
 
 
15631
        h_varname = duk_require_hstring(ctx, -1);  /* XXX: tostring? */
 
15632
        DUK_ASSERT(h_varname != NULL);
 
15633
 
 
15634
        act = duk_hthread_get_current_activation(thr);
 
15635
        if (act) {
 
15636
                (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag);  /* -> [ ... varname val this ] */
 
15637
        } else {
 
15638
                /* Outside any activation -> look up from global. */
 
15639
                DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
 
15640
                (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
 
15641
        }
 
15642
 
 
15643
        /* [ ... varname val this ]  (because throw_flag == 1, always resolved) */
 
15644
 
 
15645
        duk_pop(ctx);
 
15646
        duk_remove(ctx, -2);
 
15647
 
 
15648
        /* [ ... val ] */
 
15649
 
 
15650
        /* Return value would be pointless: because throw_flag==1, we always
 
15651
         * throw if the identifier doesn't resolve.
 
15652
         */
 
15653
        return;
 
15654
}
 
15655
 
 
15656
void duk_put_var(duk_context *ctx) {
 
15657
        duk_hthread *thr = (duk_hthread *) ctx;
 
15658
        duk_activation *act;
 
15659
        duk_hstring *h_varname;
 
15660
        duk_tval *tv_val;
 
15661
        duk_small_int_t throw_flag;
 
15662
 
 
15663
        DUK_ASSERT(ctx != NULL);
 
15664
 
 
15665
        h_varname = duk_require_hstring(ctx, -2);  /* XXX: tostring? */
 
15666
        DUK_ASSERT(h_varname != NULL);
 
15667
 
 
15668
        tv_val = duk_require_tval(ctx, -1);
 
15669
 
 
15670
        throw_flag = duk_is_strict_call(ctx);
 
15671
 
 
15672
        act = duk_hthread_get_current_activation(thr);
 
15673
        if (act) {
 
15674
                duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag);  /* -> [ ... varname val this ] */
 
15675
        } else {
 
15676
                /* Outside any activation -> put to global. */
 
15677
                DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
 
15678
                duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
 
15679
        }
 
15680
 
 
15681
        /* [ ... varname val ] */
 
15682
 
 
15683
        duk_pop_2(ctx);
 
15684
 
 
15685
        /* [ ... ] */
 
15686
 
 
15687
        return;
 
15688
}
 
15689
 
 
15690
duk_bool_t duk_del_var(duk_context *ctx) {
 
15691
        DUK_ERROR((duk_hthread *) ctx, DUK_ERR_UNIMPLEMENTED_ERROR, "unimplemented");
 
15692
        return 0;
 
15693
}
 
15694
 
 
15695
duk_bool_t duk_has_var(duk_context *ctx) {
 
15696
        DUK_ERROR((duk_hthread *) ctx, DUK_ERR_UNIMPLEMENTED_ERROR, "unimplemented");
 
15697
        return 0;
 
15698
}
 
15699
 
 
15700
#line 1 "duk_bi_array.c"
 
15701
/*
 
15702
 *  Array built-ins
 
15703
 *
 
15704
 *  Note that most Array built-ins are intentionally generic and work even
 
15705
 *  when the 'this' binding is not an Array instance.  To ensure this,
 
15706
 *  Array algorithms do not assume "magical" Array behavior for the "length"
 
15707
 *  property, for instance.
 
15708
 *
 
15709
 *  FIXME: the "Throw" flag should be set for (almost?) all [[Put]] and
 
15710
 *  [[Delete]] operations, but it's currently false throughout.  C typing
 
15711
 *  is incorrect in several places, and array lengths above 2G won't work
 
15712
 *  reliably.  Further, some valid array length values may be above 2**32-1,
 
15713
 *  and this is not always correctly handled.
 
15714
 *
 
15715
 *  On using "put" vs. "def" prop
 
15716
 *  =============================
 
15717
 *
 
15718
 *  Code below must be careful to use the appropriate primitive as it matters
 
15719
 *  for compliance.  When using "put" there may be inherited properties in
 
15720
 *  Array.prototype which cause side effects when values are written.  When
 
15721
 *  using "define" there are no such side effects, and many test262 test cases
 
15722
 *  check for this (for real world code, such side effects are very rare).
 
15723
 *  Both "put" and "define" are used in the E5.1 specification; as a rule,
 
15724
 *  "put" is used when modifying an existing array (or a non-array 'this'
 
15725
 *  binding) and "define" for setting values into a fresh result array.
 
15726
 *
 
15727
 *  Also note that Array instance 'length' should be writable, but not
 
15728
 *  enumerable and definitely not configurable: even Duktape code internally
 
15729
 *  assumes that an Array instance will always have a 'length' property.
 
15730
 *  Preventing deletion of the property is critical.
 
15731
 */
 
15732
 
 
15733
/* include removed: duk_internal.h */
 
15734
 
 
15735
/* Perform an intermediate join when this many elements have been pushed
 
15736
 * on the value stack.
 
15737
 */
 
15738
#define  DUK__ARRAY_MID_JOIN_LIMIT  4096
 
15739
 
 
15740
/* Shared entry code for many Array built-ins.  Note that length is left
 
15741
 * on stack (it could be popped, but that's not necessary).
 
15742
 */
 
15743
static unsigned int duk__push_this_obj_len_u32(duk_context *ctx) {
 
15744
        unsigned int len;
 
15745
 
 
15746
        (void) duk_push_this_coercible_to_object(ctx);
 
15747
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
 
15748
        len = duk_to_uint32(ctx, -1);
 
15749
 
 
15750
        /* -> [ ... ToObject(this) ToUint32(length) ] */
 
15751
        return len;
 
15752
}
 
15753
 
 
15754
/*
 
15755
 *  Constructor
 
15756
 */
 
15757
 
 
15758
int duk_bi_array_constructor(duk_context *ctx) {
 
15759
        int nargs;
 
15760
        double d;
 
15761
        duk_uint32_t len;
 
15762
        int i;
 
15763
 
 
15764
        nargs = duk_get_top(ctx);
 
15765
        duk_push_array(ctx);
 
15766
 
 
15767
        if (nargs == 1 && duk_is_number(ctx, 0)) {
 
15768
                /* FIXME: expensive check (also shared elsewhere - so add a shared internal API call?) */
 
15769
                d = duk_get_number(ctx, 0);
 
15770
                len = duk_to_uint32(ctx, 0);
 
15771
                if (((double) len) != d) {
 
15772
                        return DUK_RET_RANGE_ERROR;
 
15773
                }
 
15774
 
 
15775
                /* FIXME: if 'len' is low, may want to ensure array part is kept:
 
15776
                 * the caller is likely to want a dense array.
 
15777
                 */
 
15778
                duk_dup(ctx, 0);
 
15779
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);  /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
 
15780
                return 1;
 
15781
        }
 
15782
 
 
15783
        /* FIXME: optimize by creating array into correct size directly, and
 
15784
         * operating on the array part directly; values can be memcpy()'d from
 
15785
         * value stack directly as long as refcounts are increased.
 
15786
         */
 
15787
        for (i = 0; i < nargs; i++) {
 
15788
                duk_dup(ctx, i);
 
15789
                duk_def_prop_index(ctx, -2, i, DUK_PROPDESC_FLAGS_WEC);
 
15790
        }
 
15791
 
 
15792
        duk_push_number(ctx, (double) nargs);  /* FIXME: push_u32 */
 
15793
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
 
15794
        return 1;
 
15795
}
 
15796
 
 
15797
/*
 
15798
 *  isArray()
 
15799
 */
 
15800
 
 
15801
int duk_bi_array_constructor_is_array(duk_context *ctx) {
 
15802
        duk_hobject *h;
 
15803
 
 
15804
        h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
 
15805
        duk_push_boolean(ctx, (h != NULL));
 
15806
        return 1;
 
15807
}
 
15808
 
 
15809
/*
 
15810
 *  toString()
 
15811
 */
 
15812
 
 
15813
int duk_bi_array_prototype_to_string(duk_context *ctx) {
 
15814
        (void) duk_push_this_coercible_to_object(ctx);
 
15815
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
 
15816
 
 
15817
        /* [ ... this func ] */
 
15818
        if (!duk_is_callable(ctx, -1)) {
 
15819
                /* Fall back to the initial (original) Object.toString().  We don't
 
15820
                 * currently have pointers to the built-in functions, only the top
 
15821
                 * level global objects (like "Array") so this is now done in a bit
 
15822
                 * of a hacky manner.  It would be cleaner to push the (original)
 
15823
                 * function and use duk_call_method().
 
15824
                 */
 
15825
 
 
15826
                /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
 
15827
                 * but should have no visible side effects.
 
15828
                 */
 
15829
                DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString");
 
15830
                duk_set_top(ctx, 0);
 
15831
                return duk_bi_object_prototype_to_string(ctx);
 
15832
        }
 
15833
 
 
15834
        /* [ ... this func ] */
 
15835
 
 
15836
        duk_insert(ctx, -2);
 
15837
 
 
15838
        /* [ ... func this ] */
 
15839
 
 
15840
        DUK_DDDPRINT("calling: func=%!iT, this=%!iT", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
15841
        duk_call_method(ctx, 0);
 
15842
 
 
15843
        return 1;
 
15844
}
 
15845
 
 
15846
/*
 
15847
 *  concat()
 
15848
 */
 
15849
 
 
15850
int duk_bi_array_prototype_concat(duk_context *ctx) {
 
15851
        int i, n;
 
15852
        int j, len;
 
15853
        int idx, idx_last;
 
15854
        duk_hobject *h;
 
15855
 
 
15856
        /* XXX: the insert here is a bit expensive if there are a lot of items.
 
15857
         * It could also be special cased in the outermost for loop quite easily
 
15858
         * (as the element is dup()'d anyway).
 
15859
         */
 
15860
 
 
15861
        (void) duk_push_this_coercible_to_object(ctx);
 
15862
        duk_insert(ctx, 0);
 
15863
        n = duk_get_top(ctx);
 
15864
        duk_push_array(ctx);  /* -> [ ToObject(this) item1 ... itemN arr ] */
 
15865
 
 
15866
        /* NOTE: The Array special behaviors are NOT invoked by duk_def_prop_index()
 
15867
         * (which differs from the official algorithm).  If no error is thrown, this
 
15868
         * doesn't matter as the length is updated at the end.  However, if an error
 
15869
         * is thrown, the length will be unset.  That shouldn't matter because the
 
15870
         * caller won't get a reference to the intermediate value.
 
15871
         */
 
15872
 
 
15873
        idx = 0;
 
15874
        idx_last = 0;
 
15875
        for (i = 0; i < n; i++) {
 
15876
                DUK_ASSERT_TOP(ctx, n + 1);
 
15877
 
 
15878
                /* [ ToObject(this) item1 ... itemN arr ] */
 
15879
 
 
15880
                duk_dup(ctx, i);
 
15881
                h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
 
15882
                if (!h) {
 
15883
                        duk_def_prop_index(ctx, -2, idx++, DUK_PROPDESC_FLAGS_WEC);
 
15884
                        idx_last = idx;
 
15885
                        continue;
 
15886
                }
 
15887
 
 
15888
                /* [ ToObject(this) item1 ... itemN arr item(i) ] */
 
15889
 
 
15890
                /* FIXME: an array can have length higher than 32 bits; this is not handled
 
15891
                 * correctly now (also len is signed so length above 2**31-1 will have trouble.
 
15892
                 */
 
15893
                len = duk_get_length(ctx, -1);
 
15894
                for (j = 0; j < len; j++) {
 
15895
                        if (duk_get_prop_index(ctx, -1, j)) {
 
15896
                                /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
 
15897
                                duk_def_prop_index(ctx, -3, idx++, DUK_PROPDESC_FLAGS_WEC);
 
15898
                                idx_last = idx;
 
15899
                        } else {
 
15900
                                /* XXX: according to E5.1 Section 15.4.4.4 nonexistent trailing
 
15901
                                 * elements do not affect 'length' but test262 disagrees.  Work
 
15902
                                 * as E5.1 mandates for now and don't touch idx_last.
 
15903
                                 */
 
15904
                                idx++;
 
15905
                                duk_pop(ctx);
 
15906
                        }
 
15907
                }
 
15908
                duk_pop(ctx);
 
15909
        }
 
15910
 
 
15911
        duk_push_number(ctx, (double) idx_last);
 
15912
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
 
15913
 
 
15914
        DUK_ASSERT_TOP(ctx, n + 1);
 
15915
        return 1;
 
15916
}
 
15917
 
 
15918
/*
 
15919
 *  join(), toLocaleString()
 
15920
 *
 
15921
 *  Note: checking valstack is necessary, but only in the per-element loop.
 
15922
 *
 
15923
 *  Note: the trivial approach of pushing all the elements on the value stack
 
15924
 *  and then calling duk_join() fails when the array contains a large number
 
15925
 *  of elements.  This problem can't be offloaded to duk_join() because the
 
15926
 *  elements to join must be handled here and have special handling.  Current
 
15927
 *  approach is to do intermediate joins with very large number of elements.
 
15928
 *  There is no fancy handling; the prefix gets re-joined multiple times.
 
15929
 */
 
15930
 
 
15931
int duk_bi_array_prototype_join_shared(duk_context *ctx) {
 
15932
        duk_uint32_t len, count;
 
15933
        duk_uint32_t idx;
 
15934
        duk_small_int_t to_locale_string = duk_get_magic(ctx);
 
15935
        duk_int_t valstack_required;
 
15936
 
 
15937
        /* For join(), nargs is 1.  For toLocaleString(), nargs is 0 and
 
15938
         * setting the top essentially pushes an undefined to the stack,
 
15939
         * thus defaulting to a comma separator.
 
15940
         */
 
15941
        duk_set_top(ctx, 1);
 
15942
        if (duk_is_undefined(ctx, 0)) {
 
15943
                duk_pop(ctx);
 
15944
                duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
 
15945
        } else {
 
15946
                duk_to_string(ctx, 0);
 
15947
        }
 
15948
 
 
15949
        len = duk__push_this_obj_len_u32(ctx);
 
15950
 
 
15951
        /* [ sep ToObject(this) len ] */
 
15952
 
 
15953
        DUK_DDDPRINT("sep=%!T, this=%!T, len=%d",
 
15954
                     duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), (int) len);
 
15955
 
 
15956
        valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
 
15957
                             DUK__ARRAY_MID_JOIN_LIMIT : len);
 
15958
        valstack_required++;
 
15959
        duk_require_stack(ctx, valstack_required);
 
15960
 
 
15961
        duk_dup(ctx, 0);
 
15962
 
 
15963
        /* [ sep ToObject(this) len sep ] */
 
15964
 
 
15965
        count = 0;
 
15966
        idx = 0;
 
15967
        for (;;) {
 
15968
                if (count >= DUK__ARRAY_MID_JOIN_LIMIT ||   /* intermediate join to avoid valstack overflow */
 
15969
                    idx >= len) { /* end of loop (careful with len==0) */
 
15970
                        /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
 
15971
                        DUK_DDDPRINT("mid/final join, count=%d, idx=%d, len=%d",
 
15972
                                     (int) count, (int) idx, (int) len);
 
15973
                        duk_join(ctx, count);  /* -> [ sep ToObject(this) len str ] */
 
15974
                        duk_dup(ctx, 0);       /* -> [ sep ToObject(this) len str sep ] */
 
15975
                        duk_insert(ctx, -2);   /* -> [ sep ToObject(this) len sep str ] */
 
15976
                        count = 1;
 
15977
                }
 
15978
                if (idx >= len) {
 
15979
                        /* if true, the stack already contains the final result */
 
15980
                        break;
 
15981
                }
 
15982
 
 
15983
                duk_get_prop_index(ctx, 1, idx);
 
15984
                if (duk_is_null_or_undefined(ctx, -1)) {
 
15985
                        duk_pop(ctx);
 
15986
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
15987
                } else {
 
15988
                        if (to_locale_string) {
 
15989
                                duk_to_object(ctx, -1);
 
15990
                                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
 
15991
                                duk_insert(ctx, -2);  /* -> [ ... toLocaleString ToObject(val) ] */
 
15992
                                duk_call_method(ctx, 0);
 
15993
                                duk_to_string(ctx, -1);
 
15994
                        } else {
 
15995
                                duk_to_string(ctx, -1);
 
15996
                        }
 
15997
                }
 
15998
 
 
15999
                count++;
 
16000
                idx++;
 
16001
        }
 
16002
 
 
16003
        /* [ sep ToObject(this) len sep result ] */
 
16004
 
 
16005
        return 1;
 
16006
}
 
16007
 
 
16008
/*
 
16009
 *  pop(), push()
 
16010
 */
 
16011
 
 
16012
int duk_bi_array_prototype_pop(duk_context *ctx) {
 
16013
        unsigned int len;
 
16014
        unsigned int idx;
 
16015
 
 
16016
        DUK_ASSERT_TOP(ctx, 0);
 
16017
        len = duk__push_this_obj_len_u32(ctx);
 
16018
        if (len == 0) {
 
16019
                duk_push_int(ctx, 0);
 
16020
                duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);  /* FIXME: Throw */
 
16021
                return 0;
 
16022
        }
 
16023
        idx = len - 1;
 
16024
 
 
16025
        duk_get_prop_index(ctx, 0, idx);
 
16026
        duk_del_prop_index(ctx, 0, idx);  /* FIXME: Throw */
 
16027
        duk_push_int(ctx, idx);  /* FIXME: unsigned */
 
16028
        duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);  /* FIXME: Throw */
 
16029
        return 1;
 
16030
}
 
16031
 
 
16032
int duk_bi_array_prototype_push(duk_context *ctx) {
 
16033
        /* Note: 'this' is not necessarily an Array object.  The push()
 
16034
         * algorithm is supposed to work for other kinds of objects too,
 
16035
         * so the algorithm has e.g. an explicit update for the 'length'
 
16036
         * property which is normally "magical" in arrays.
 
16037
         */
 
16038
 
 
16039
        double len;
 
16040
        int i, n;
 
16041
 
 
16042
        n = duk_get_top(ctx);
 
16043
        len = (double) duk__push_this_obj_len_u32(ctx);
 
16044
 
 
16045
        /* [ arg1 ... argN obj length ] */
 
16046
 
 
16047
        /* Note: we keep track of length with a double instead of a 32-bit
 
16048
         * (unsigned) int because the length can go beyond 32 bits and the
 
16049
         * final length value is NOT wrapped to 32 bits on this call.
 
16050
         */
 
16051
 
 
16052
        for (i = 0; i < n; i++) {
 
16053
                duk_push_number(ctx, len);
 
16054
                duk_dup(ctx, i);
 
16055
                duk_put_prop(ctx, -4);  /* FIXME: "Throw" */
 
16056
                len += 1.0;
 
16057
        }
 
16058
 
 
16059
        duk_push_number(ctx, len);
 
16060
        duk_dup_top(ctx);
 
16061
        duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
 
16062
 
 
16063
        /* [ arg1 ... argN obj length new_length ] */
 
16064
        return 1;
 
16065
}
 
16066
 
 
16067
/*
 
16068
 *  sort()
 
16069
 *
 
16070
 *  Currently qsort with random pivot.  This is now really, really slow,
 
16071
 *  because there is no fast path for array parts.
 
16072
 */
 
16073
 
 
16074
static int duk__array_sort_compare(duk_context *ctx, int idx1, int idx2) {
 
16075
        int have1, have2;
 
16076
        int undef1, undef2;
 
16077
        int ret;
 
16078
        int idx_obj = 1, idx_fn = 0;  /* fixed offsets in valstack */
 
16079
        duk_hstring *h1, *h2;
 
16080
 
 
16081
        /* Fast exit if indices are identical.  This is valid for a non-existent property,
 
16082
         * for an undefined value, and almost always for ToString() coerced comparison of
 
16083
         * arbitrary values (corner cases where this is not the case include e.g. a an
 
16084
         * object with varying ToString() coercion).
 
16085
         *
 
16086
         * The specification does not prohibit "caching" of values read from the array, so
 
16087
         * assuming equality for comparing an index with itself falls into the category of
 
16088
         * "caching".
 
16089
         *
 
16090
         * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
 
16091
         * have an effect on the final result.  The specification does not require any
 
16092
         * specific behavior for inconsistent compare functions, so again, this fast path
 
16093
         * is OK.
 
16094
         */
 
16095
 
 
16096
        if (idx1 == idx2) {
 
16097
                DUK_DDDPRINT("duk__array_sort_compare: idx1=%d, idx2=%d -> indices identical, quick exit", idx1, idx2);
 
16098
                return 0;
 
16099
        }
 
16100
 
 
16101
        have1 = duk_get_prop_index(ctx, idx_obj, idx1);
 
16102
        have2 = duk_get_prop_index(ctx, idx_obj, idx2);
 
16103
 
 
16104
        DUK_DDDPRINT("duk__array_sort_compare: idx1=%d, idx2=%d, have1=%d, have2=%d, val1=%!T, val2=%!T",
 
16105
                     idx1, idx2, have1, have2, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
16106
 
 
16107
        if (have1) {
 
16108
                if (have2) {
 
16109
                        ;
 
16110
                } else {
 
16111
                        ret = -1;
 
16112
                        goto pop_ret;
 
16113
                }
 
16114
        } else {
 
16115
                if (have2) {
 
16116
                        ret = 1;
 
16117
                        goto pop_ret;
 
16118
                } else {
 
16119
                        ret = 0;
 
16120
                        goto pop_ret;
 
16121
                }
 
16122
        }
 
16123
 
 
16124
        undef1 = duk_is_undefined(ctx, -2);
 
16125
        undef2 = duk_is_undefined(ctx, -1);
 
16126
        if (undef1) {
 
16127
                if (undef2) {
 
16128
                        ret = 0;
 
16129
                        goto pop_ret;
 
16130
                } else {
 
16131
                        ret = 1;
 
16132
                        goto pop_ret;
 
16133
                }
 
16134
        } else {
 
16135
                if (undef2) {
 
16136
                        ret = -1;
 
16137
                        goto pop_ret;
 
16138
                } else {
 
16139
                        ;
 
16140
                }
 
16141
        }
 
16142
 
 
16143
        if (!duk_is_undefined(ctx, idx_fn)) {
 
16144
                double d;
 
16145
 
 
16146
                /* no need to check callable; duk_call() will do that */
 
16147
                duk_dup(ctx, idx_fn);    /* -> [ ... x y fn ] */
 
16148
                duk_insert(ctx, -3);     /* -> [ ... fn x y ] */
 
16149
                duk_call(ctx, 2);        /* -> [ ... res ] */
 
16150
 
 
16151
                /* The specification is a bit vague what to do if the return
 
16152
                 * value is not a number.  Other implementations seem to
 
16153
                 * tolerate non-numbers but e.g. V8 won't apparently do a
 
16154
                 * ToNumber().
 
16155
                 */
 
16156
 
 
16157
                /* FIXME: best behavior for real world compatibility? */
 
16158
 
 
16159
                d = duk_to_number(ctx, -1);
 
16160
                if (d < 0.0) {
 
16161
                        ret = -1;
 
16162
                } else if (d > 0.0) {
 
16163
                        ret = 1;
 
16164
                } else {
 
16165
                        ret = 0;
 
16166
                }
 
16167
 
 
16168
                duk_pop(ctx);
 
16169
                DUK_DDDPRINT("-> result %d (from comparefn, after coercion)", ret);
 
16170
                return ret;
 
16171
        }
 
16172
 
 
16173
        /* string compare is the default (a bit oddly) */
 
16174
 
 
16175
        h1 = duk_to_hstring(ctx, -2);
 
16176
        h2 = duk_to_hstring(ctx, -1);
 
16177
        DUK_ASSERT(h1 != NULL);
 
16178
        DUK_ASSERT(h2 != NULL);
 
16179
 
 
16180
        ret = duk_js_string_compare(h1, h2);  /* retval is directly usable */
 
16181
        goto pop_ret;
 
16182
 
 
16183
 pop_ret:
 
16184
        duk_pop_2(ctx);
 
16185
        DUK_DDDPRINT("-> result %d", ret);
 
16186
        return ret;
 
16187
}
 
16188
 
 
16189
static void duk__array_sort_swap(duk_context *ctx, int l, int r) {
 
16190
        int have_l, have_r;
 
16191
        int idx_obj = 1;  /* fixed offsets in valstack */
 
16192
 
 
16193
        if (l == r) {
 
16194
                return;
 
16195
        }
 
16196
 
 
16197
        /* swap elements; deal with non-existent elements correctly */
 
16198
        have_l = duk_get_prop_index(ctx, idx_obj, l);
 
16199
        have_r = duk_get_prop_index(ctx, idx_obj, r);
 
16200
 
 
16201
        if (have_r) {
 
16202
                /* right exists, [[Put]] regardless whether or not left exists */
 
16203
                duk_put_prop_index(ctx, idx_obj, l);
 
16204
        } else {
 
16205
                duk_del_prop_index(ctx, idx_obj, l);
 
16206
                duk_pop(ctx);
 
16207
        }
 
16208
 
 
16209
        if (have_l) {
 
16210
                duk_put_prop_index(ctx, idx_obj, r);
 
16211
        } else {
 
16212
                duk_del_prop_index(ctx, idx_obj, r);
 
16213
                duk_pop(ctx);
 
16214
        }
 
16215
}
 
16216
 
 
16217
#ifdef DUK_USE_DDDEBUG
 
16218
/* Debug print which visualizes the qsort partitioning process. */
 
16219
static void duk__debuglog_qsort_state(duk_context *ctx, int lo, int hi, int pivot) {
 
16220
        char buf[4096];
 
16221
        char *ptr = buf;
 
16222
        int i, n;
 
16223
        n = duk_get_length(ctx, 1);
 
16224
        if (n > 4000) {
 
16225
                n = 4000;
 
16226
        }
 
16227
        *ptr++ = '[';
 
16228
        for (i = 0; i < n; i++) {
 
16229
                if (i == pivot) {
 
16230
                        *ptr++ = '|';
 
16231
                } else if (i == lo) {
 
16232
                        *ptr++ = '<';
 
16233
                } else if (i == hi) {
 
16234
                        *ptr++ = '>';
 
16235
                } else if (i >= lo && i <= hi) {
 
16236
                        *ptr++ = '-';
 
16237
                } else {
 
16238
                        *ptr++ = ' ';
 
16239
                }
 
16240
        }
 
16241
        *ptr++ = ']';
 
16242
        *ptr++ = '\0';
 
16243
 
 
16244
        DUK_DDDPRINT("%s   (lo=%d, hi=%d, pivot=%d)", buf, lo, hi, pivot);
 
16245
}
 
16246
#endif
 
16247
 
 
16248
static void duk__array_qsort(duk_context *ctx, int lo, int hi) {
 
16249
        duk_hthread *thr = (duk_hthread *) ctx;
 
16250
        int p, l, r;
 
16251
 
 
16252
        DUK_DDDPRINT("duk__array_qsort: lo=%d, hi=%d, obj=%!T", lo, hi, duk_get_tval(ctx, 1));
 
16253
 
 
16254
        DUK_ASSERT_TOP(ctx, 3);
 
16255
 
 
16256
        /* In some cases it may be that lo > hi, or hi < 0; these
 
16257
         * degenerate cases happen e.g. for empty arrays, and in
 
16258
         * recursion leaves.
 
16259
         */
 
16260
 
 
16261
        /* trivial cases */
 
16262
        if (hi - lo < 1) {
 
16263
                DUK_DDDPRINT("degenerate case, return immediately");
 
16264
                return;
 
16265
        }
 
16266
        DUK_ASSERT(hi > lo);
 
16267
        DUK_ASSERT(hi - lo + 1 >= 2);
 
16268
 
 
16269
        /* randomized pivot selection */
 
16270
        p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1));  /* rnd in [lo,hi] */
 
16271
        DUK_ASSERT(p >= lo && p <= hi);
 
16272
        DUK_DDDPRINT("lo=%d, hi=%d, chose pivot p=%d", lo, hi, p);
 
16273
 
 
16274
        /* move pivot out of the way */
 
16275
        duk__array_sort_swap(ctx, p, lo);
 
16276
        p = lo;
 
16277
        DUK_DDDPRINT("pivot moved out of the way: %!T", duk_get_tval(ctx, 1));
 
16278
 
 
16279
        l = lo + 1;
 
16280
        r = hi;
 
16281
        for (;;) {
 
16282
                /* find elements to swap */
 
16283
                for (;;) {
 
16284
                        DUK_DDDPRINT("left scan: l=%d, r=%d, p=%d", l, r, p);
 
16285
                        if (l >= hi) {
 
16286
                                break;
 
16287
                        }
 
16288
                        if (duk__array_sort_compare(ctx, l, p) >= 0) {  /* !(l < p) */
 
16289
                                break;
 
16290
                        }
 
16291
                        l++;
 
16292
                }
 
16293
                for (;;) {
 
16294
                        DUK_DDDPRINT("right scan: l=%d, r=%d, p=%d", l, r, p);
 
16295
                        if (r <= lo) {
 
16296
                                break;
 
16297
                        }
 
16298
                        if (duk__array_sort_compare(ctx, p, r) >= 0) {  /* !(p < r) */
 
16299
                                break;
 
16300
                        }
 
16301
                        r--;
 
16302
                }
 
16303
                if (l >= r) {
 
16304
                        goto done;
 
16305
                }
 
16306
                DUK_ASSERT(l < r);
 
16307
 
 
16308
                DUK_DDDPRINT("swap %d and %d", l, r);
 
16309
 
 
16310
                duk__array_sort_swap(ctx, l, r);
 
16311
 
 
16312
                DUK_DDDPRINT("after swap: %!T", duk_get_tval(ctx, 1));
 
16313
                l++;
 
16314
                r--;
 
16315
        }
 
16316
 done:
 
16317
        /* Note that 'l' and 'r' may cross, i.e. r < l */
 
16318
        DUK_ASSERT(l >= lo && l <= hi);
 
16319
        DUK_ASSERT(r >= lo && r <= hi);
 
16320
 
 
16321
        /* FIXME: there's no explicit recursion bound here now.  For the average
 
16322
         * qsort recursion depth O(log n) that's not really necessary: e.g. for
 
16323
         * 2**32 recursion depth would be about 32 which is OK.  However, qsort
 
16324
         * worst case recursion depth is O(n) which may be a problem.
 
16325
         */
 
16326
 
 
16327
        /* move pivot to its final place */
 
16328
        DUK_DDDPRINT("before final pivot swap: %!T", duk_get_tval(ctx, 1));
 
16329
        duk__array_sort_swap(ctx, lo, r);       
 
16330
 
 
16331
#ifdef DUK_USE_DDDEBUG
 
16332
        duk__debuglog_qsort_state(ctx, lo, hi, r);
 
16333
#endif
 
16334
 
 
16335
        DUK_DDDPRINT("recurse: pivot=%d, obj=%!T", r, duk_get_tval(ctx, 1));
 
16336
        duk__array_qsort(ctx, lo, r - 1);
 
16337
        duk__array_qsort(ctx, r + 1, hi);
 
16338
}
 
16339
 
 
16340
int duk_bi_array_prototype_sort(duk_context *ctx) {
 
16341
        unsigned int len;
 
16342
 
 
16343
        len = duk__push_this_obj_len_u32(ctx);
 
16344
 
 
16345
        /* stack[0] = compareFn
 
16346
         * stack[1] = ToObject(this)
 
16347
         * stack[2] = ToUint32(length)
 
16348
         */
 
16349
 
 
16350
        duk__array_qsort(ctx, 0, len - 1);
 
16351
 
 
16352
        DUK_ASSERT_TOP(ctx, 3);
 
16353
        duk_pop(ctx);
 
16354
        return 1;  /* return ToObject(this) */
 
16355
}
 
16356
 
 
16357
/*
 
16358
 *  splice()
 
16359
 */
 
16360
 
 
16361
/* FIXME: this compiles to over 500 bytes now, even without special handling
 
16362
 * for an array part.  Uses signed ints so does not handle full array range correctly.
 
16363
 */
 
16364
 
 
16365
/* FIXME: can shift() / unshift() use the same helper?
 
16366
 *   shift() is (close to?) <--> splice(0, 1)
 
16367
 *   unshift is (close to?) <--> splice(0, 0, [items])?
 
16368
 */
 
16369
 
 
16370
int duk_bi_array_prototype_splice(duk_context *ctx) {
 
16371
        int nargs;
 
16372
        int have_delcount;
 
16373
        int item_count;
 
16374
        int len;
 
16375
        int act_start;
 
16376
        int del_count;
 
16377
        int i;
 
16378
 
 
16379
        DUK_UNREF(have_delcount);
 
16380
 
 
16381
        nargs = duk_get_top(ctx);
 
16382
        if (nargs < 2) {
 
16383
                duk_set_top(ctx, 2);
 
16384
                nargs = 2;
 
16385
                have_delcount = 0;
 
16386
        } else {
 
16387
                have_delcount = 1;
 
16388
        }
 
16389
 
 
16390
        len = duk__push_this_obj_len_u32(ctx);
 
16391
 
 
16392
        act_start = duk_to_int_clamped(ctx, 0, -len, len);
 
16393
        if (act_start < 0) {
 
16394
                act_start = len + act_start;
 
16395
        }
 
16396
        DUK_ASSERT(act_start >= 0 && act_start <= len);
 
16397
 
 
16398
#ifdef DUK_USE_ARRAY_SPLICE_NONSTD_DELCOUNT
 
16399
        if (have_delcount) {
 
16400
#endif
 
16401
                del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
 
16402
#ifdef DUK_USE_ARRAY_SPLICE_NONSTD_DELCOUNT
 
16403
        } else {
 
16404
                /* E5.1 standard behavior when deleteCount is not given would be
 
16405
                 * to treat it just like if 'undefined' was given, which coerces
 
16406
                 * ultimately to 0.  Real world behavior is to splice to the end
 
16407
                 * of array, see test-bi-array-proto-splice-no-delcount.js.
 
16408
                 */
 
16409
                del_count = len - act_start;
 
16410
        }
 
16411
#endif
 
16412
 
 
16413
        DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
 
16414
        DUK_ASSERT(del_count + act_start <= len);
 
16415
 
 
16416
        duk_push_array(ctx);
 
16417
 
 
16418
        /* stack[0] = start
 
16419
         * stack[1] = deleteCount
 
16420
         * stack[2...nargs-1] = items
 
16421
         * stack[nargs] = ToObject(this)               -3
 
16422
         * stack[nargs+1] = ToUint32(length)           -2
 
16423
         * stack[nargs+2] = result array               -1
 
16424
         */
 
16425
 
 
16426
        DUK_ASSERT_TOP(ctx, nargs + 3);
 
16427
 
 
16428
        /* Step 9: copy elements-to-be-deleted into the result array */
 
16429
 
 
16430
        for (i = 0; i < del_count; i++) {
 
16431
                if (duk_get_prop_index(ctx, -3, act_start + i)) {
 
16432
                        duk_def_prop_index(ctx, -2, i, DUK_PROPDESC_FLAGS_WEC);  /* throw flag irrelevant (false in std alg) */
 
16433
                } else {
 
16434
                        duk_pop(ctx);
 
16435
                }
 
16436
        }
 
16437
        duk_push_int(ctx, del_count);  /* FIXME: typing */
 
16438
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
 
16439
 
 
16440
        /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
 
16441
 
 
16442
        DUK_ASSERT(nargs >= 2);
 
16443
        item_count = nargs - 2;
 
16444
        if (item_count < del_count) {
 
16445
                /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 1
 
16446
                 * -> [ A B F G H ]          (conceptual intermediate step)
 
16447
                 * -> [ A B . F G H ]        (placeholder marked)
 
16448
                 *    [ A B C F G H ]        (actual result at this point, C will be replaced)
 
16449
                 */
 
16450
 
 
16451
                DUK_ASSERT_TOP(ctx, nargs + 3);
 
16452
 
 
16453
                for (i = act_start; i < len - del_count; i++) {
 
16454
                        if (duk_get_prop_index(ctx, -3, i + del_count)) {
 
16455
                                duk_put_prop_index(ctx, -4, i + item_count);  /* FIXME: Throw */
 
16456
                        } else {
 
16457
                                duk_pop(ctx);
 
16458
                                duk_del_prop_index(ctx, -3, i + item_count);  /* FIXME: Throw */
 
16459
                        }
 
16460
                }
 
16461
 
 
16462
                DUK_ASSERT_TOP(ctx, nargs + 3);
 
16463
 
 
16464
                /* loop iterator init and limit changed from standard algorithm */
 
16465
                for (i = len - 1; i >= len - del_count + item_count; i--) {
 
16466
                        duk_del_prop_index(ctx, -3, i);  /* FIXME: Throw */
 
16467
                }
 
16468
 
 
16469
                DUK_ASSERT_TOP(ctx, nargs + 3);
 
16470
        } else if (item_count > del_count) {
 
16471
                /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 4
 
16472
                 * -> [ A B F G H ]          (conceptual intermediate step)
 
16473
                 * -> [ A B . . . . F G H ]  (placeholder marked)
 
16474
                 *    [ A B C D E F F G H ]  (actual result at this point)
 
16475
                 */
 
16476
 
 
16477
                DUK_ASSERT_TOP(ctx, nargs + 3);
 
16478
 
 
16479
                /* loop iterator init and limit changed from standard algorithm */
 
16480
                for (i = len - del_count - 1; i >= act_start; i--) {
 
16481
                        if (duk_get_prop_index(ctx, -3, i + del_count)) {
 
16482
                                duk_put_prop_index(ctx, -4, i + item_count);  /* FIXME: Throw */
 
16483
                        } else {
 
16484
                                duk_pop(ctx);
 
16485
                                duk_del_prop_index(ctx, -3, i + item_count);  /* FIXME: Throw */
 
16486
                        }
 
16487
                }
 
16488
 
 
16489
                DUK_ASSERT_TOP(ctx, nargs + 3);
 
16490
        } else {
 
16491
                /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 3
 
16492
                 * -> [ A B F G H ]          (conceptual intermediate step)
 
16493
                 * -> [ A B . . . F G H ]    (placeholder marked)
 
16494
                 *    [ A B C D E F G H ]    (actual result at this point)
 
16495
                 */
 
16496
        }
 
16497
        DUK_ASSERT_TOP(ctx, nargs + 3);
 
16498
 
 
16499
        /* Step 15: insert itemCount elements into the hole made above */
 
16500
 
 
16501
        for (i = 0; i < item_count; i++) {
 
16502
                duk_dup(ctx, i + 2);  /* args start at index 2 */
 
16503
                duk_put_prop_index(ctx, -4, act_start + i);  /* FIXME: Throw */
 
16504
        }
 
16505
 
 
16506
        /* Step 16: update length; note that the final length may be above 32 bit range */
 
16507
 
 
16508
        duk_push_number(ctx, ((double) len) - ((double) del_count) + ((double) item_count));
 
16509
        duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
 
16510
 
 
16511
        /* result array is already at the top of stack */
 
16512
        DUK_ASSERT_TOP(ctx, nargs + 3);
 
16513
        return 1;
 
16514
}
 
16515
 
 
16516
/*
 
16517
 *  reverse()
 
16518
 */
 
16519
 
 
16520
int duk_bi_array_prototype_reverse(duk_context *ctx) {
 
16521
        unsigned int len;
 
16522
        unsigned int middle;
 
16523
        unsigned int lower, upper;
 
16524
        int have_lower, have_upper;
 
16525
 
 
16526
        len = duk__push_this_obj_len_u32(ctx);
 
16527
        middle = len / 2;
 
16528
 
 
16529
        for (lower = 0; lower < middle; lower++) {
 
16530
                DUK_ASSERT_TOP(ctx, 2);
 
16531
 
 
16532
                upper = len - lower - 1;
 
16533
 
 
16534
                have_lower = duk_get_prop_index(ctx, -2, lower);
 
16535
                have_upper = duk_get_prop_index(ctx, -3, upper);
 
16536
 
 
16537
                /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
 
16538
 
 
16539
                if (have_upper) {
 
16540
                        duk_put_prop_index(ctx, -4, lower);  /* FIXME: Throw */
 
16541
                } else {
 
16542
                        duk_del_prop_index(ctx, -4, lower);
 
16543
                        duk_pop(ctx);
 
16544
                }
 
16545
 
 
16546
                if (have_lower) {
 
16547
                        duk_put_prop_index(ctx, -3, upper);
 
16548
                } else {
 
16549
                        duk_del_prop_index(ctx, -3, upper);
 
16550
                        duk_pop(ctx);
 
16551
                }
 
16552
 
 
16553
                DUK_ASSERT_TOP(ctx, 2);
 
16554
        }
 
16555
 
 
16556
        DUK_ASSERT_TOP(ctx, 2);
 
16557
        duk_pop(ctx);  /* -> [ ToObject(this) ] */
 
16558
        return 1;
 
16559
}
 
16560
 
 
16561
/*
 
16562
 *  slice()
 
16563
 */
 
16564
 
 
16565
int duk_bi_array_prototype_slice(duk_context *ctx) {
 
16566
        unsigned int len;
 
16567
        int start, end;
 
16568
        int idx;
 
16569
        int i;
 
16570
        duk_uint32_t res_length = 0;
 
16571
 
 
16572
        len = duk__push_this_obj_len_u32(ctx);
 
16573
        duk_push_array(ctx);
 
16574
 
 
16575
        /* stack[0] = start
 
16576
         * stack[1] = end
 
16577
         * stack[2] = ToObject(this)
 
16578
         * stack[3] = ToUint32(length)
 
16579
         * stack[4] = result array
 
16580
         */
 
16581
 
 
16582
        start = duk_to_int_clamped(ctx, 0, -len, len);  /* FIXME: does not support full 32-bit range */
 
16583
        if (start < 0) {
 
16584
                start = len + start;
 
16585
        }
 
16586
        /* FIXME: could duk_is_undefined() provide defaulting undefined to 'len'
 
16587
         * (the upper limit)?
 
16588
         */
 
16589
        if (duk_is_undefined(ctx, 1)) {
 
16590
                end = len;
 
16591
        } else {
 
16592
                end = duk_to_int_clamped(ctx, 1, -len, len);
 
16593
                if (end < 0) {
 
16594
                        end = len + end;
 
16595
                }
 
16596
        }
 
16597
        DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
 
16598
        DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
 
16599
 
 
16600
        idx = 0;
 
16601
        for (i = start; i < end; i++) {
 
16602
                DUK_ASSERT_TOP(ctx, 5);
 
16603
                if (duk_get_prop_index(ctx, 2, i)) {
 
16604
                        duk_def_prop_index(ctx, 4, idx, DUK_PROPDESC_FLAGS_WEC);
 
16605
                        res_length = idx + 1;
 
16606
                } else {
 
16607
                        duk_pop(ctx);
 
16608
                }
 
16609
                idx++;
 
16610
                DUK_ASSERT_TOP(ctx, 5);
 
16611
        }
 
16612
 
 
16613
        duk_push_int(ctx, res_length);  /* FIXME */
 
16614
        duk_def_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
 
16615
 
 
16616
        DUK_ASSERT_TOP(ctx, 5);
 
16617
        return 1;
 
16618
}
 
16619
 
 
16620
/*
 
16621
 *  shift()
 
16622
 */
 
16623
 
 
16624
int duk_bi_array_prototype_shift(duk_context *ctx) {
 
16625
        unsigned int len;
 
16626
        unsigned int i;
 
16627
 
 
16628
        len = duk__push_this_obj_len_u32(ctx);
 
16629
        if (len == 0) {
 
16630
                duk_push_int(ctx, 0);
 
16631
                duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);  /* FIXME: Throw */
 
16632
                return 0;
 
16633
        }
 
16634
 
 
16635
        duk_get_prop_index(ctx, 0, 0);
 
16636
 
 
16637
        /* stack[0] = object (this)
 
16638
         * stack[1] = ToUint32(length)
 
16639
         * stack[2] = elem at index 0 (retval)
 
16640
         */
 
16641
 
 
16642
        for (i = 1; i < len; i++) {
 
16643
                DUK_ASSERT_TOP(ctx, 3);
 
16644
                if (duk_get_prop_index(ctx, 0, i)) {
 
16645
                        /* fromPresent = true */
 
16646
                        duk_put_prop_index(ctx, 0, i - 1);  /* FIXME: Throw */
 
16647
                } else {
 
16648
                        /* fromPresent = false */
 
16649
                        duk_del_prop_index(ctx, 0, i - 1);
 
16650
                        duk_pop(ctx);
 
16651
                }
 
16652
        }
 
16653
        duk_del_prop_index(ctx, 0, len - 1);  /* FIXME: Throw */
 
16654
 
 
16655
        duk_push_number(ctx, (double) (len - 1));  /* FIXME: push uint */
 
16656
        duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
 
16657
 
 
16658
        DUK_ASSERT_TOP(ctx, 3);
 
16659
        return 1;
 
16660
}
 
16661
 
 
16662
/*
 
16663
 *  unshift()
 
16664
 */
 
16665
 
 
16666
int duk_bi_array_prototype_unshift(duk_context *ctx) {
 
16667
        unsigned int nargs;
 
16668
        unsigned int len;
 
16669
        unsigned int i;
 
16670
        double final_len;
 
16671
 
 
16672
        /* FIXME: duk_get_top return type */
 
16673
        nargs = (unsigned int) duk_get_top(ctx);
 
16674
        len = duk__push_this_obj_len_u32(ctx);
 
16675
 
 
16676
        /* stack[0...nargs-1] = unshift args (vararg)
 
16677
         * stack[nargs] = ToObject(this)
 
16678
         * stack[nargs+1] = ToUint32(length)
 
16679
         */
 
16680
 
 
16681
        DUK_ASSERT_TOP(ctx, nargs + 2);
 
16682
 
 
16683
        /* Note: unshift() may operate on indices above unsigned 32-bit range
 
16684
         * and the final length may be >= 2**32.  Hence we use 'double' vars
 
16685
         * here, when appropriate.
 
16686
         */
 
16687
 
 
16688
        i = len;
 
16689
        while (i > 0) {
 
16690
                DUK_ASSERT_TOP(ctx, nargs + 2);
 
16691
                i--;
 
16692
                duk_push_number(ctx, ((double) i) + ((double) nargs));  /* k+argCount-1; note that may be above 32-bit range */
 
16693
                if (duk_get_prop_index(ctx, -3, i)) {
 
16694
                        /* fromPresent = true */
 
16695
                        /* [ ... ToObject(this) ToUint32(length) to val ] */
 
16696
                        duk_put_prop(ctx, -4);  /* -> [ ... ToObject(this) ToUint32(length) ] */  /* FIXME: Throw */
 
16697
                } else {
 
16698
                        /* fromPresent = false */
 
16699
                        /* [ ... ToObject(this) ToUint32(length) to val ] */
 
16700
                        duk_pop(ctx);
 
16701
                        duk_del_prop(ctx, -3);  /* -> [ ... ToObject(this) ToUint32(length) ] */  /* FIXME: Throw */
 
16702
                }
 
16703
                DUK_ASSERT_TOP(ctx, nargs + 2);
 
16704
        }
 
16705
 
 
16706
        for (i = 0; i < nargs; i++) {
 
16707
                DUK_ASSERT_TOP(ctx, nargs + 2);
 
16708
                duk_dup(ctx, i);  /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
 
16709
                duk_put_prop_index(ctx, -3, i);  /* FIXME: Throw */
 
16710
                DUK_ASSERT_TOP(ctx, nargs + 2);
 
16711
        }
 
16712
 
 
16713
        DUK_ASSERT_TOP(ctx, nargs + 2);
 
16714
        final_len = ((double) len) + ((double) nargs);
 
16715
        duk_push_number(ctx, final_len);
 
16716
        duk_dup_top(ctx);  /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
 
16717
        duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);  /* FIXME: Throw */
 
16718
        return 1;
 
16719
}
 
16720
 
 
16721
/*
 
16722
 *  indexOf(), lastIndexOf()
 
16723
 */
 
16724
 
 
16725
int duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
 
16726
        /* FIXME: types, ensure loop below works when fixed (i must be able to go negative right now) */
 
16727
        int nargs;
 
16728
        int i, len;
 
16729
        int fromIndex;
 
16730
        int idx_step = duk_get_magic(ctx);  /* idx_step is +1 for indexOf, -1 for lastIndexOf */
 
16731
 
 
16732
        /* lastIndexOf() needs to be a vararg function because we must distinguish
 
16733
         * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
 
16734
         * made vararg for symmetry although it doesn't strictly need to be.
 
16735
         */
 
16736
 
 
16737
        nargs = duk_get_top(ctx);
 
16738
        duk_set_top(ctx, 2);
 
16739
 
 
16740
        len = duk__push_this_obj_len_u32(ctx);
 
16741
        if (len == 0) {
 
16742
                goto not_found;
 
16743
        }
 
16744
 
 
16745
        /* Index clamping is a bit tricky, we must ensure that we'll only iterate
 
16746
         * through elements that exist and that the specific requirements from E5.1
 
16747
         * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
 
16748
         *
 
16749
         *   - indexOf: clamp to [-len,len], negative handling -> [0,len],
 
16750
         *     if clamped result is len, for-loop bails out immediately
 
16751
         *
 
16752
         *   - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
 
16753
         *     if clamped result is -1, for-loop bails out immediately
 
16754
         *
 
16755
         * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
 
16756
         * for indexOf() but incorrect for lastIndexOf().  Hence special handling,
 
16757
         * and why lastIndexOf() needs to be a vararg function.
 
16758
         */
 
16759
 
 
16760
        if (nargs >= 2) {
 
16761
                /* indexOf: clamp fromIndex to [-len, len]
 
16762
                 * (if fromIndex == len, for-loop terminates directly)
 
16763
                 *
 
16764
                 * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
 
16765
                 * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
 
16766
                 */
 
16767
                fromIndex = duk_to_int_clamped(ctx,
 
16768
                                               1,
 
16769
                                               (idx_step > 0 ? -len : -len - 1),
 
16770
                                               (idx_step > 0 ? len : len - 1));
 
16771
                if (fromIndex < 0) {
 
16772
                        /* for lastIndexOf, result may be -1 (mark immediate termination) */
 
16773
                        fromIndex = len + fromIndex;
 
16774
                }
 
16775
        } else {
 
16776
                /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
 
16777
                 * handle both indexOf and lastIndexOf specially here.
 
16778
                 */
 
16779
                if (idx_step > 0) {
 
16780
                        fromIndex = 0;
 
16781
                } else {
 
16782
                        fromIndex = len - 1;
 
16783
                }
 
16784
        }
 
16785
 
 
16786
        /* stack[0] = searchElement
 
16787
         * stack[1] = fromIndex
 
16788
         * stack[2] = object
 
16789
         * stack[3] = length (not needed, but not popped above)
 
16790
         */
 
16791
 
 
16792
        for (i = fromIndex;
 
16793
             i >= 0 && i < len;
 
16794
             i += idx_step) {
 
16795
                DUK_ASSERT_TOP(ctx, 4);
 
16796
 
 
16797
                if (duk_get_prop_index(ctx, 2, i)) {
 
16798
                        DUK_ASSERT_TOP(ctx, 5);
 
16799
                        if (duk_strict_equals(ctx, 0, 4)) {
 
16800
                                duk_push_int(ctx, i);
 
16801
                                return 1;
 
16802
                        }
 
16803
                }
 
16804
 
 
16805
                duk_pop(ctx);
 
16806
        }
 
16807
 
 
16808
 not_found:
 
16809
        duk_push_int(ctx, -1);
 
16810
        return 1;
 
16811
}
 
16812
 
 
16813
/*
 
16814
 *  every(), some(), forEach(), map(), filter()
 
16815
 */
 
16816
 
 
16817
#define DUK__ITER_EVERY    0
 
16818
#define DUK__ITER_SOME     1
 
16819
#define DUK__ITER_FOREACH  2
 
16820
#define DUK__ITER_MAP      3
 
16821
#define DUK__ITER_FILTER   4
 
16822
 
 
16823
/* XXX: This helper is a bit awkward because the handling for the different iteration
 
16824
 * callers is quite different.  This now compiles to a bit less than 500 bytes, so with
 
16825
 * 5 callers the net result is about 100 bytes / caller.
 
16826
 */
 
16827
 
 
16828
int duk_bi_array_prototype_iter_shared(duk_context *ctx) {
 
16829
        int len;
 
16830
        int i;
 
16831
        int k;
 
16832
        int bval;
 
16833
        int iter_type = duk_get_magic(ctx);
 
16834
        duk_uint32_t res_length = 0;
 
16835
 
 
16836
        /* each call this helper serves has nargs==2 */
 
16837
        DUK_ASSERT_TOP(ctx, 2);
 
16838
 
 
16839
        len = duk__push_this_obj_len_u32(ctx);
 
16840
        if (!duk_is_callable(ctx, 0)) {
 
16841
                goto type_error;
 
16842
        }
 
16843
        /* if thisArg not supplied, behave as if undefined was supplied */
 
16844
 
 
16845
        if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
 
16846
                duk_push_array(ctx);
 
16847
        } else {
 
16848
                duk_push_undefined(ctx);
 
16849
        }
 
16850
 
 
16851
        /* stack[0] = callback
 
16852
         * stack[1] = thisArg
 
16853
         * stack[2] = object
 
16854
         * stack[3] = ToUint32(length)  (unused, but avoid unnecessary pop)
 
16855
         * stack[4] = result array (or undefined)
 
16856
         */
 
16857
 
 
16858
        k = 0;  /* result index for filter() */
 
16859
        for (i = 0; i < len; i++) {
 
16860
                DUK_ASSERT_TOP(ctx, 5);
 
16861
 
 
16862
                if (!duk_get_prop_index(ctx, 2, i)) {
 
16863
                        duk_pop(ctx);
 
16864
                        continue;
 
16865
                }
 
16866
 
 
16867
                /* The original value needs to be preserved for filter(), hence
 
16868
                 * this funny order.  We can't re-get the value because of side
 
16869
                 * effects.
 
16870
                 */
 
16871
 
 
16872
                duk_dup(ctx, 0);
 
16873
                duk_dup(ctx, 1);
 
16874
                duk_dup(ctx, -3);
 
16875
                duk_push_int(ctx, i);
 
16876
                duk_dup(ctx, 2);  /* [ ... val callback thisArg val i obj ] */
 
16877
                duk_call_method(ctx, 3); /* -> [ ... val retval ] */
 
16878
 
 
16879
                switch (iter_type) {
 
16880
                case DUK__ITER_EVERY:
 
16881
                        bval = duk_to_boolean(ctx, -1);
 
16882
                        if (!bval) {
 
16883
                                /* stack top contains 'false' */
 
16884
                                return 1;
 
16885
                        }
 
16886
                        break;
 
16887
                case DUK__ITER_SOME:
 
16888
                        bval = duk_to_boolean(ctx, -1);
 
16889
                        if (bval) {
 
16890
                                /* stack top contains 'true' */
 
16891
                                return 1;
 
16892
                        }
 
16893
                        break;
 
16894
                case DUK__ITER_FOREACH:
 
16895
                        /* nop */
 
16896
                        break;
 
16897
                case DUK__ITER_MAP:
 
16898
                        duk_dup(ctx, -1);
 
16899
                        duk_def_prop_index(ctx, 4, i, DUK_PROPDESC_FLAGS_WEC);  /* retval to result[i] */
 
16900
                        res_length = i + 1;
 
16901
                        break;
 
16902
                case DUK__ITER_FILTER:
 
16903
                        bval = duk_to_boolean(ctx, -1);
 
16904
                        if (bval) {
 
16905
                                duk_dup(ctx, -2);  /* orig value */
 
16906
                                duk_def_prop_index(ctx, 4, k, DUK_PROPDESC_FLAGS_WEC);
 
16907
                                k++;
 
16908
                                res_length = k;
 
16909
                        }
 
16910
                        break;
 
16911
                default:
 
16912
                        DUK_UNREACHABLE();
 
16913
                        break;
 
16914
                }
 
16915
                duk_pop_2(ctx);
 
16916
 
 
16917
                DUK_ASSERT_TOP(ctx, 5);
 
16918
        }
 
16919
 
 
16920
        switch (iter_type) {
 
16921
        case DUK__ITER_EVERY:
 
16922
                duk_push_true(ctx);
 
16923
                break;
 
16924
        case DUK__ITER_SOME:
 
16925
                duk_push_false(ctx);
 
16926
                break;
 
16927
        case DUK__ITER_FOREACH:
 
16928
                duk_push_undefined(ctx);
 
16929
                break;
 
16930
        case DUK__ITER_MAP:
 
16931
        case DUK__ITER_FILTER:
 
16932
                DUK_ASSERT_TOP(ctx, 5);
 
16933
                DUK_ASSERT(duk_is_array(ctx, -1));  /* topmost element is the result array already */
 
16934
                duk_push_number(ctx, (double) res_length);  /* FIXME */
 
16935
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
 
16936
                break;
 
16937
        default:
 
16938
                DUK_UNREACHABLE();
 
16939
                break;
 
16940
        }
 
16941
 
 
16942
        return 1;
 
16943
 
 
16944
 type_error:
 
16945
        return DUK_RET_TYPE_ERROR;
 
16946
}
 
16947
 
 
16948
/*
 
16949
 *  reduce(), reduceRight()
 
16950
 */
 
16951
 
 
16952
int duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
 
16953
        int nargs;
 
16954
        int have_acc;
 
16955
        int i, len;
 
16956
        int idx_step = duk_get_magic(ctx);  /* idx_step is +1 for reduce, -1 for reduceRight */
 
16957
 
 
16958
        /* We're a varargs function because we need to detect whether
 
16959
         * initialValue was given or not.
 
16960
         */
 
16961
        nargs = duk_get_top(ctx);
 
16962
        DUK_DPRINT("nargs=%d", nargs);
 
16963
 
 
16964
        duk_set_top(ctx, 2);
 
16965
        len = duk__push_this_obj_len_u32(ctx);
 
16966
        if (!duk_is_callable(ctx, 0)) {
 
16967
                goto type_error;
 
16968
        }
 
16969
 
 
16970
        /* stack[0] = callback fn
 
16971
         * stack[1] = initialValue
 
16972
         * stack[2] = object (coerced this)
 
16973
         * stack[3] = length (not needed, but not popped above)
 
16974
         * stack[4] = accumulator
 
16975
         */
 
16976
 
 
16977
        have_acc = 0;
 
16978
        if (nargs >= 2) {
 
16979
                duk_dup(ctx, 1);
 
16980
                have_acc = 1;
 
16981
        }
 
16982
        DUK_DPRINT("have_acc=%d, acc=%!T", have_acc, duk_get_tval(ctx, 3));
 
16983
 
 
16984
        for (i = (idx_step >= 0 ? 0 : len - 1);
 
16985
             i >= 0 && i < len;
 
16986
             i += idx_step) {
 
16987
                DUK_DPRINT("i=%d, len=%d, have_acc=%d, top=%d, acc=%!T",
 
16988
                           i, len, have_acc, duk_get_top(ctx), duk_get_tval(ctx, 4));
 
16989
 
 
16990
                DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
 
16991
                           (!have_acc && duk_get_top(ctx) == 4));
 
16992
 
 
16993
                if (!duk_has_prop_index(ctx, 2, i)) {
 
16994
                        continue;
 
16995
                }
 
16996
 
 
16997
                if (!have_acc) {
 
16998
                        DUK_ASSERT_TOP(ctx, 4);
 
16999
                        duk_get_prop_index(ctx, 2, i);
 
17000
                        have_acc = 1;
 
17001
                        DUK_ASSERT_TOP(ctx, 5);
 
17002
                } else {
 
17003
                        DUK_ASSERT_TOP(ctx, 5);
 
17004
                        duk_dup(ctx, 0);
 
17005
                        duk_dup(ctx, 4);
 
17006
                        duk_get_prop_index(ctx, 2, i);
 
17007
                        duk_push_int(ctx, i);  /* FIXME: type */
 
17008
                        duk_dup(ctx, 2);
 
17009
                        DUK_DPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
 
17010
                                   duk_get_tval(ctx, -5), duk_get_tval(ctx, -4), duk_get_tval(ctx, -3),
 
17011
                                   duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
17012
                        duk_call(ctx, 4);
 
17013
                        DUK_DPRINT("-> result: %!T", duk_get_tval(ctx, -1));
 
17014
                        duk_replace(ctx, 4);
 
17015
                        DUK_ASSERT_TOP(ctx, 5);
 
17016
                }
 
17017
        }
 
17018
 
 
17019
        if (!have_acc) {
 
17020
                goto type_error;
 
17021
        }
 
17022
 
 
17023
        DUK_ASSERT_TOP(ctx, 5);
 
17024
        return 1;
 
17025
 
 
17026
 type_error:
 
17027
        return DUK_RET_TYPE_ERROR;
 
17028
}
 
17029
 
 
17030
#line 1 "duk_bi_boolean.c"
 
17031
/*
 
17032
 *  Boolean built-ins
 
17033
 */
 
17034
 
 
17035
/* include removed: duk_internal.h */
 
17036
 
 
17037
/* Shared helper to provide toString() and valueOf().  Checks 'this', gets
 
17038
 * the primitive value to stack top, and optionally coerces with ToString().
 
17039
 */
 
17040
int duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
 
17041
        duk_tval *tv;
 
17042
        duk_hobject *h;
 
17043
        int coerce_tostring = duk_get_magic(ctx);
 
17044
 
 
17045
        /* FIXME: there is room to use a shared helper here, many built-ins
 
17046
         * check the 'this' type, and if it's an object, check its class,
 
17047
         * then get its internal value, etc.
 
17048
         */
 
17049
 
 
17050
        duk_push_this(ctx);
 
17051
        tv = duk_get_tval(ctx, -1);
 
17052
        DUK_ASSERT(tv != NULL);
 
17053
 
 
17054
        if (DUK_TVAL_IS_BOOLEAN(tv)) {
 
17055
                goto type_ok;
 
17056
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
17057
                h = DUK_TVAL_GET_OBJECT(tv);
 
17058
                DUK_ASSERT(h != NULL);
 
17059
 
 
17060
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
 
17061
                        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
17062
                        DUK_ASSERT(duk_is_boolean(ctx, -1));
 
17063
                        goto type_ok;
 
17064
                }
 
17065
        }
 
17066
 
 
17067
        return DUK_RET_TYPE_ERROR;
 
17068
 
 
17069
 type_ok:
 
17070
        if (coerce_tostring) {
 
17071
                duk_to_string(ctx, -1);
 
17072
        }
 
17073
        return 1;
 
17074
}
 
17075
 
 
17076
int duk_bi_boolean_constructor(duk_context *ctx) {
 
17077
        duk_hobject *h_this;
 
17078
 
 
17079
        duk_to_boolean(ctx, 0);
 
17080
 
 
17081
        if (duk_is_constructor_call(ctx)) {
 
17082
                /* FIXME: helper; rely on Boolean.prototype as being non-writable, non-configurable */
 
17083
                duk_push_this(ctx);
 
17084
                h_this = duk_get_hobject(ctx, -1);
 
17085
                DUK_ASSERT(h_this != NULL);
 
17086
                DUK_ASSERT(h_this->prototype == ((duk_hthread *) ctx)->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
 
17087
 
 
17088
                DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
 
17089
 
 
17090
                duk_dup(ctx, 0);  /* -> [ val obj val ] */
 
17091
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);  /* FIXME: proper flags? */
 
17092
        }  /* unbalanced stack */
 
17093
 
 
17094
        return 1;
 
17095
}
 
17096
 
 
17097
#line 1 "duk_bi_buffer.c"
 
17098
/*
 
17099
 *  Buffer built-ins
 
17100
 */
 
17101
 
 
17102
/* include removed: duk_internal.h */
 
17103
 
 
17104
/*
 
17105
 *  Constructor
 
17106
 */
 
17107
 
 
17108
int duk_bi_buffer_constructor(duk_context *ctx) {
 
17109
        duk_size_t buf_size;
 
17110
        duk_small_int_t buf_dynamic;
 
17111
        duk_uint8_t *buf_data;
 
17112
        const duk_uint8_t *src_data;
 
17113
        duk_hobject *h_obj;
 
17114
 
 
17115
        /*
 
17116
         *  Constructor arguments are currently somewhat compatible with
 
17117
         *  (keep it that way if possible):
 
17118
         *
 
17119
         *    http://nodejs.org/api/buffer.html
 
17120
         *
 
17121
         */
 
17122
 
 
17123
        buf_dynamic = duk_get_boolean(ctx, 1);  /* default to false */
 
17124
 
 
17125
        switch (duk_get_type(ctx, 0)) {
 
17126
        case DUK_TYPE_NUMBER:
 
17127
                /* new buffer of specified size */
 
17128
                buf_size = (duk_size_t) duk_to_int(ctx, 0);
 
17129
                (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
 
17130
                break;
 
17131
        case DUK_TYPE_BUFFER:
 
17132
                /* return input buffer, converted to a Buffer object if called as a
 
17133
                 * constructor (no change if called as a function).
 
17134
                 */
 
17135
                duk_set_top(ctx, 1);
 
17136
                break;
 
17137
        case DUK_TYPE_STRING:
 
17138
                /* new buffer with string contents */
 
17139
                src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
 
17140
                DUK_ASSERT(src_data != NULL);  /* even for zero-length string */
 
17141
                buf_data = duk_push_buffer(ctx, buf_size, buf_dynamic);
 
17142
                DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
 
17143
                break;
 
17144
        case DUK_TYPE_OBJECT:
 
17145
                /* Buffer object: get the plain buffer inside.  If called as as
 
17146
                 * constructor, a new Buffer object pointing to the same plain
 
17147
                 * buffer is created below.
 
17148
                 */
 
17149
                h_obj = duk_get_hobject(ctx, 0);
 
17150
                DUK_ASSERT(h_obj != NULL);
 
17151
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) != DUK_HOBJECT_CLASS_BUFFER) {
 
17152
                        return DUK_RET_TYPE_ERROR;
 
17153
                }
 
17154
                duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_VALUE);
 
17155
                DUK_ASSERT(duk_is_buffer(ctx, -1));
 
17156
                break;
 
17157
        case DUK_TYPE_NONE:
 
17158
        default:
 
17159
                return DUK_RET_TYPE_ERROR;
 
17160
        }
 
17161
 
 
17162
        /* stack is unbalanced, but: [ <something> buf ] */
 
17163
 
 
17164
        if (duk_is_constructor_call(ctx)) {
 
17165
                duk_push_object_helper(ctx,
 
17166
                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
 
17167
                                       DUK_HOBJECT_FLAG_SPECIAL_BUFFEROBJ |
 
17168
                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
 
17169
                                       DUK_BIDX_BUFFER_PROTOTYPE);
 
17170
 
 
17171
                /* Buffer object internal value is immutable */
 
17172
                duk_dup(ctx, -2);
 
17173
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
 
17174
        }
 
17175
        /* Note: unbalanced stack on purpose */
 
17176
 
 
17177
        return 1;
 
17178
}
 
17179
 
 
17180
/*
 
17181
 *  toString(), valueOf()
 
17182
 */
 
17183
 
 
17184
int duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
 
17185
        duk_tval *tv;
 
17186
        int to_string = duk_get_magic(ctx);
 
17187
 
 
17188
        duk_push_this(ctx);
 
17189
        tv = duk_require_tval(ctx, -1);
 
17190
        DUK_ASSERT(tv != NULL);
 
17191
 
 
17192
        if (DUK_TVAL_IS_BUFFER(tv)) {
 
17193
                /* nop */
 
17194
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
17195
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
17196
                DUK_ASSERT(h != NULL);
 
17197
 
 
17198
                /* Must be a "buffer object", i.e. class "Buffer" */
 
17199
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_BUFFER) {
 
17200
                        goto type_error;
 
17201
                }
 
17202
 
 
17203
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
17204
        } else {
 
17205
                goto type_error;
 
17206
        }
 
17207
 
 
17208
        if (to_string) {
 
17209
                duk_to_string(ctx, -1);
 
17210
        }
 
17211
        return 1;
 
17212
 
 
17213
 type_error:
 
17214
        return DUK_RET_TYPE_ERROR;
 
17215
}
 
17216
 
 
17217
#line 1 "duk_bi_date.c"
 
17218
/*
 
17219
 *  Date built-ins
 
17220
 *
 
17221
 *  Unlike most built-ins, Date has a lot of platform dependencies for
 
17222
 *  getting UTC time, converting between UTC and local time, and parsing
 
17223
 *  and formatting time values.
 
17224
 *
 
17225
 *  See doc/datetime.txt.
 
17226
 *
 
17227
 *  Platform specific links:
 
17228
 *
 
17229
 *    - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
 
17230
 */
 
17231
 
 
17232
/* include removed: duk_internal.h */
 
17233
 
 
17234
/*
 
17235
 *  Platform specific includes and defines
 
17236
 *
 
17237
 *  Note that necessary system headers (like <sys/time.h>) are included
 
17238
 *  by duk_internal.h (or duk_features.h, which is included by duk_internal.h)
 
17239
 *  because the header locations vary between systems and we don't want
 
17240
 *  that clutter here.
 
17241
 */
 
17242
 
 
17243
#define DUK__GET_NOW_TIMEVAL      duk_bi_date_get_now
 
17244
#define DUK__GET_LOCAL_TZOFFSET   duk__get_local_tzoffset
 
17245
 
 
17246
/* Buffer sizes for some UNIX calls.  Larger than strictly necessary
 
17247
 * to avoid Valgrind errors.
 
17248
 */
 
17249
#define DUK__STRPTIME_BUF_SIZE  64
 
17250
#define DUK__STRFTIME_BUF_SIZE  64
 
17251
 
 
17252
/*
 
17253
 *  Other file level defines
 
17254
 */
 
17255
 
 
17256
/* Forward declarations. */
 
17257
static double duk__push_this_get_timeval_tzoffset(duk_context *ctx, int flags, int *out_tzoffset);
 
17258
static double duk__push_this_get_timeval(duk_context *ctx, int flags);
 
17259
static void duk__timeval_to_parts(double d, int *parts, double *dparts, int flags);
 
17260
static double duk__get_timeval_from_dparts(double *dparts, int flags);
 
17261
static void duk__twodigit_year_fixup(duk_context *ctx, int idx_val);
 
17262
 
 
17263
/* Millisecond count constants. */
 
17264
#define DUK__MS_SECOND          1000
 
17265
#define DUK__MS_MINUTE          (60 * 1000)
 
17266
#define DUK__MS_HOUR            (60 * 60 * 1000)
 
17267
#define DUK__MS_DAY             (24 * 60 * 60 * 1000)
 
17268
 
 
17269
/* Part indices for internal breakdowns.  Part order from DUK__IDX_YEAR to
 
17270
 * DUK__IDX_MILLISECOND matches argument ordering of Ecmascript API calls
 
17271
 * (like Date constructor call).  A few functions in this file depend
 
17272
 * on the specific ordering, so change with care.
 
17273
 *
 
17274
 * (Must be in-sync with genbuiltins.py.)
 
17275
 */
 
17276
#define DUK__IDX_YEAR           0  /* year */
 
17277
#define DUK__IDX_MONTH          1  /* month: 0 to 11 */
 
17278
#define DUK__IDX_DAY            2  /* day within month: 0 to 30 */
 
17279
#define DUK__IDX_HOUR           3
 
17280
#define DUK__IDX_MINUTE         4
 
17281
#define DUK__IDX_SECOND         5
 
17282
#define DUK__IDX_MILLISECOND    6
 
17283
#define DUK__IDX_WEEKDAY        7  /* weekday: 0 to 6, 0=sunday, 1=monday, etc */
 
17284
#define DUK__NUM_PARTS          8
 
17285
 
 
17286
/* Internal API call flags, used for various functions in this file.
 
17287
 * Certain flags are used by only certain functions, but since the flags
 
17288
 * don't overlap, a single flags value can be passed around to multiple
 
17289
 * functions.
 
17290
 *
 
17291
 * The unused top bits of the flags field are also used to pass values
 
17292
 * to helpers (duk__get_part_helper() and duk__set_part_helper()).
 
17293
 *
 
17294
 * (Must be in-sync with genbuiltins.py.)
 
17295
 */
 
17296
#define DUK__FLAG_NAN_TO_ZERO          (1 << 0)  /* timeval breakdown: internal time value NaN -> zero */
 
17297
#define DUK__FLAG_NAN_TO_RANGE_ERROR   (1 << 1)  /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */
 
17298
#define DUK__FLAG_ONEBASED             (1 << 2)  /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */
 
17299
#define DUK__FLAG_LOCALTIME            (1 << 3)  /* convert time value to local time */
 
17300
#define DUK__FLAG_SUB1900              (1 << 4)  /* getter: subtract 1900 from year when getting year part */
 
17301
#define DUK__FLAG_TOSTRING_DATE        (1 << 5)  /* include date part in string conversion result */
 
17302
#define DUK__FLAG_TOSTRING_TIME        (1 << 6)  /* include time part in string conversion result */
 
17303
#define DUK__FLAG_TOSTRING_LOCALE      (1 << 7)  /* use locale specific formatting if available */
 
17304
#define DUK__FLAG_TIMESETTER           (1 << 8)  /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */
 
17305
#define DUK__FLAG_YEAR_FIXUP           (1 << 9)  /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */
 
17306
#define DUK__FLAG_SEP_T                (1 << 10) /* string conversion: use 'T' instead of ' ' as a separator */
 
17307
 
 
17308
/*
 
17309
 *  Platform specific helpers
 
17310
 */
 
17311
 
 
17312
#ifdef DUK_USE_DATE_NOW_GETTIMEOFDAY
 
17313
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
 
17314
duk_double_t duk_bi_date_get_now(duk_context *ctx) {
 
17315
        duk_hthread *thr = (duk_hthread *) ctx;
 
17316
        struct timeval tv;
 
17317
        double d;
 
17318
 
 
17319
        if (gettimeofday(&tv, NULL) != 0) {
 
17320
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "gettimeofday failed");
 
17321
        }
 
17322
 
 
17323
        d = ((double) tv.tv_sec) * 1000.0 +
 
17324
            ((double) (tv.tv_usec / 1000));
 
17325
        DUK_ASSERT(DUK_FLOOR(d) == d);  /* no fractions */
 
17326
 
 
17327
        return d;
 
17328
}
 
17329
#endif  /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
 
17330
 
 
17331
#ifdef DUK_USE_DATE_NOW_TIME
 
17332
/* Not a very good provider: only full seconds are available. */
 
17333
duk_double_t duk_bi_date_get_now(duk_context *ctx) {
 
17334
        time_t t = time(NULL);
 
17335
        return ((double) t) * 1000.0;
 
17336
}
 
17337
#endif  /* DUK_USE_DATE_NOW_TIME */
 
17338
 
 
17339
#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
 
17340
/* Shared Windows helpers. */
 
17341
static void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
 
17342
        FILETIME ft;
 
17343
        if (SystemTimeToFileTime(st, &ft) == 0) {
 
17344
                DUK_DPRINT("SystemTimeToFileTime() failed, returning 0");
 
17345
                res->QuadPart = 0;
 
17346
        } else {
 
17347
                res->LowPart = ft.dwLowDateTime;
 
17348
                res->HighPart = ft.dwHighDateTime;
 
17349
        }
 
17350
}
 
17351
static void duk__set_systime_jan1970(SYSTEMTIME *st) {
 
17352
        DUK_MEMZERO((void *) st, sizeof(*st));
 
17353
        st->wYear = 1970;
 
17354
        st->wMonth = 1;
 
17355
        st->wDayOfWeek = 4;  /* not sure whether or not needed; Thursday */
 
17356
        st->wDay = 1;
 
17357
        DUK_ASSERT(st->wHour == 0);
 
17358
        DUK_ASSERT(st->wMinute == 0);
 
17359
        DUK_ASSERT(st->wSecond == 0);
 
17360
        DUK_ASSERT(st->wMilliseconds == 0);
 
17361
}
 
17362
#endif  /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
 
17363
 
 
17364
#ifdef DUK_USE_DATE_NOW_WINDOWS
 
17365
duk_double_t duk_bi_date_get_now(duk_context *ctx) {
 
17366
        /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
 
17367
         * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
 
17368
         */
 
17369
        SYSTEMTIME st1, st2;
 
17370
        ULARGE_INTEGER tmp1, tmp2;
 
17371
 
 
17372
        GetSystemTime(&st1);
 
17373
        duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
 
17374
 
 
17375
        duk__set_systime_jan1970(&st2);
 
17376
        duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
 
17377
 
 
17378
        /* Difference is in 100ns units, convert to milliseconds */
 
17379
        return (double) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
 
17380
}
 
17381
#endif  /* DUK_USE_DATE_NOW_WINDOWS */
 
17382
 
 
17383
#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
 
17384
/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
 
17385
static int duk__get_local_tzoffset(double d) {
 
17386
        time_t t, t1, t2;
 
17387
        int parts[DUK__NUM_PARTS];
 
17388
        double dparts[DUK__NUM_PARTS];
 
17389
        struct tm tms[2];
 
17390
#ifdef DUK_USE_DATE_TZO_GMTIME
 
17391
        struct tm *tm_ptr;
 
17392
#endif
 
17393
 
 
17394
        /* For NaN/inf, the return value doesn't matter. */
 
17395
        if (!DUK_ISFINITE(d)) {
 
17396
                return 0;
 
17397
        }
 
17398
 
 
17399
        /*
 
17400
         *  This is a bit tricky to implement portably.  The result depends
 
17401
         *  on the timestamp (specifically, DST depends on the timestamp).
 
17402
         *  If e.g. UNIX APIs are used, they'll have portability issues with
 
17403
         *  very small and very large years.
 
17404
         *
 
17405
         *  Current approach:
 
17406
         *
 
17407
         *  - Clamp year to stay within portable UNIX limits.  Avoid 2038 as
 
17408
         *    some conversions start to fail.  Avoid 1970, as some conversions
 
17409
         *    in January 1970 start to fail (verified in practice).
 
17410
         *
 
17411
         *  - Create a UTC time breakdown from 't', and then pretend it is a
 
17412
         *    local time breakdown and build a UTC time from it.  The timestamp
 
17413
         *    will effectively shift backwards by time the time offset (e.g. -2h
 
17414
         *    or -3h for EET/EEST).  Convert with mktime() twice to get the DST
 
17415
         *    flag for the final conversion.
 
17416
         *
 
17417
         *  FIXME: this is probably not entirely correct nor clear, but is
 
17418
         *  good enough for now.
 
17419
         */
 
17420
 
 
17421
        duk__timeval_to_parts(d, parts, dparts, 0 /*flags*/);
 
17422
 
 
17423
        /*
 
17424
         *  FIXME: must choose 'equivalent year', E5 Section 15.9.1.8, instead
 
17425
         *  of just clamping.
 
17426
         */
 
17427
        if (parts[DUK__IDX_YEAR] < 1971) {
 
17428
                dparts[DUK__IDX_YEAR] = 1971.0;
 
17429
        } else if (parts[DUK__IDX_YEAR] > 2037) {
 
17430
                dparts[DUK__IDX_YEAR] = 2037.0;
 
17431
        }
 
17432
 
 
17433
        d = duk__get_timeval_from_dparts(dparts, 0 /*flags*/);
 
17434
        DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0);  /* unsigned 31-bit range */
 
17435
        t = (size_t) (d / 1000.0);
 
17436
        DUK_DDDPRINT("timeval: %lf -> time_t %d", d, (int) t);
 
17437
 
 
17438
        t1 = t;
 
17439
 
 
17440
        DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
 
17441
 
 
17442
#if defined(DUK_USE_DATE_TZO_GMTIME_R)
 
17443
        (void) gmtime_r(&t, &tms[0]);
 
17444
#elif defined(DUK_USE_DATE_TZO_GMTIME)
 
17445
        tm_ptr = gmtime(&t);
 
17446
        DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
 
17447
#else
 
17448
#error internal error
 
17449
#endif
 
17450
        DUK_MEMCPY((void *) &tms[1], &tms[0], sizeof(struct tm));
 
17451
 
 
17452
        DUK_DDDPRINT("before mktime: tm={sec:%d,min:%d,hour:%d,mday:%d,mon:%d,year:%d,"
 
17453
                     "wday:%d,yday:%d,isdst:%d}",
 
17454
                     (int) tms[0].tm_sec, (int) tms[0].tm_min, (int) tms[0].tm_hour,
 
17455
                     (int) tms[0].tm_mday, (int) tms[0].tm_mon, (int) tms[0].tm_year,
 
17456
                     (int) tms[0].tm_wday, (int) tms[0].tm_yday, (int) tms[0].tm_isdst);
 
17457
 
 
17458
        (void) mktime(&tms[0]);
 
17459
        tms[1].tm_isdst = tms[0].tm_isdst;
 
17460
        t2 = mktime(&tms[1]);
 
17461
        DUK_ASSERT_DISABLE(t2 >= 0);  /* On some platforms time_t is unsigned and this would cause a warning */
 
17462
        if (t2 == (time_t) -1) {
 
17463
                /* This check used to be for (t2 < 0) but on some platforms
 
17464
                 * time_t is unsigned and apparently the proper way to detect
 
17465
                 * an mktime() error return is the cast above.  See e.g.:
 
17466
                 * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
 
17467
                 */
 
17468
                goto error;
 
17469
        }
 
17470
 
 
17471
        DUK_DDDPRINT("after mktime: tm={sec:%d,min:%d,hour:%d,mday:%d,mon:%d,year:%d,"
 
17472
                     "wday:%d,yday:%d,isdst:%d}",
 
17473
                     (int) tms[1].tm_sec, (int) tms[1].tm_min, (int) tms[1].tm_hour,
 
17474
                     (int) tms[1].tm_mday, (int) tms[1].tm_mon, (int) tms[1].tm_year,
 
17475
                     (int) tms[1].tm_wday, (int) tms[1].tm_yday, (int) tms[1].tm_isdst);
 
17476
        DUK_DDDPRINT("t2=%d", (int) t2);
 
17477
 
 
17478
        /* Positive if local time ahead of UTC. */
 
17479
 
 
17480
        /* difftime() returns a double, so coercion to int generates quite
 
17481
         * a lot of code.  Direct subtraction is not portable, however.
 
17482
         *
 
17483
         * FIXME: allow direct subtraction on known platforms.
 
17484
         */
 
17485
#if 0
 
17486
        return t1 - t2;
 
17487
#endif
 
17488
        return (int) difftime(t1, t2);
 
17489
 
 
17490
 error:
 
17491
        /* FIXME: return something more useful, so that caller can throw? */
 
17492
        DUK_DPRINT("mktime() failed, d=%lf", d);
 
17493
        return 0;
 
17494
}
 
17495
#endif  /* DUK_USE_DATE_TZO_GMTIME */
 
17496
 
 
17497
#if defined(DUK_USE_DATE_TZO_WINDOWS)
 
17498
static int duk__get_local_tzoffset(double d) {
 
17499
        SYSTEMTIME st1;
 
17500
        SYSTEMTIME st2;
 
17501
        SYSTEMTIME st3;
 
17502
        ULARGE_INTEGER tmp1;
 
17503
        ULARGE_INTEGER tmp2;
 
17504
        ULARGE_INTEGER tmp3;
 
17505
        FILETIME ft1;
 
17506
 
 
17507
        /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
 
17508
         * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
 
17509
         */
 
17510
 
 
17511
        duk__set_systime_jan1970(&st1);
 
17512
        duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
 
17513
        tmp2.QuadPart = (ULONGLONG) (d * 10000.0);  /* millisec -> 100ns units since jan 1, 1970 */
 
17514
        tmp2.QuadPart += tmp1.QuadPart;             /* input 'd' in Windows UTC, 100ns units */
 
17515
 
 
17516
        ft1.dwLowDateTime = tmp2.LowPart;
 
17517
        ft1.dwHighDateTime = tmp2.HighPart;
 
17518
        FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
 
17519
        if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
 
17520
                DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0");
 
17521
                return 0;
 
17522
        }
 
17523
        duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
 
17524
 
 
17525
        /* Positive if local time ahead of UTC. */
 
17526
        return (int) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL);  /* seconds */
 
17527
}
 
17528
#endif  /* DUK_USE_DATE_TZO_WINDOWS */
 
17529
 
 
17530
#ifdef DUK_USE_DATE_PRS_STRPTIME
 
17531
static int duk__parse_string_strptime(duk_context *ctx, const char *str) {
 
17532
        struct tm tm;
 
17533
        time_t t;
 
17534
        char buf[DUK__STRPTIME_BUF_SIZE];
 
17535
 
 
17536
        /* copy to buffer with spare to avoid Valgrind gripes from strptime */
 
17537
        DUK_ASSERT(str != NULL);
 
17538
        DUK_MEMZERO(buf, sizeof(buf));  /* valgrind whine without this */
 
17539
        DUK_SNPRINTF(buf, sizeof(buf), "%s", str);
 
17540
        buf[sizeof(buf) - 1] = (char) 0;
 
17541
 
 
17542
        DUK_DDDPRINT("parsing: '%s'", buf);
 
17543
 
 
17544
        DUK_MEMZERO(&tm, sizeof(tm));
 
17545
        if (strptime((const char *) buf, "%c", &tm) != NULL) {
 
17546
                DUK_DDDPRINT("before mktime: tm={sec:%d,min:%d,hour:%d,mday:%d,mon:%d,year:%d,"
 
17547
                             "wday:%d,yday:%d,isdst:%d}",
 
17548
                             (int) tm.tm_sec, (int) tm.tm_min, (int) tm.tm_hour,
 
17549
                             (int) tm.tm_mday, (int) tm.tm_mon, (int) tm.tm_year,
 
17550
                             (int) tm.tm_wday, (int) tm.tm_yday, (int) tm.tm_isdst);
 
17551
                tm.tm_isdst = -1;  /* negative: dst info not available */
 
17552
 
 
17553
                t = mktime(&tm);
 
17554
                DUK_DDDPRINT("mktime() -> %d", (int) t);
 
17555
                if (t >= 0) {
 
17556
                        duk_push_number(ctx, ((double) t) * 1000.0);
 
17557
                        return 1;
 
17558
                }
 
17559
        }
 
17560
 
 
17561
        return 0;
 
17562
}
 
17563
#endif  /* DUK_USE_DATE_PRS_STRPTIME */
 
17564
 
 
17565
#ifdef DUK_USE_DATE_PRS_GETDATE
 
17566
static int duk__parse_string_getdate(duk_context *ctx, const char *str) {
 
17567
        struct tm tm;
 
17568
        int rc;
 
17569
        time_t t;
 
17570
 
 
17571
        /* For this to work, DATEMSK must be set, to this is not very
 
17572
         * convenient for an embeddable interpreter.
 
17573
         */
 
17574
 
 
17575
        DUK_MEMZERO(&tm, sizeof(struct tm));
 
17576
        rc = getdate_r(str, &tm);
 
17577
        DUK_DDDPRINT("getdate_r() -> %d", rc);
 
17578
 
 
17579
        if (rc == 0) {
 
17580
                t = mktime(&tm);
 
17581
                DUK_DDDPRINT("mktime() -> %d", (int) t);
 
17582
                if (t >= 0) {
 
17583
                        duk_push_number(ctx, (double) t);
 
17584
                        return 1;
 
17585
                }
 
17586
        }
 
17587
 
 
17588
        duk_push_nan(ctx);
 
17589
        return 1;
 
17590
}
 
17591
#endif  /* DUK_USE_DATE_PRS_GETDATE */
 
17592
 
 
17593
#ifdef DUK_USE_DATE_FMT_STRFTIME
 
17594
static int duk__format_parts_strftime(duk_context *ctx, int *parts, int tzoffset, int flags) {
 
17595
        char buf[DUK__STRFTIME_BUF_SIZE];
 
17596
        struct tm tm;
 
17597
        const char *fmt;
 
17598
 
 
17599
        DUK_UNREF(tzoffset);
 
17600
 
 
17601
        /* If platform doesn't support the entire Ecmascript range, we need to
 
17602
         * return 0 so that the caller can fall back to the default formatter.
 
17603
         *
 
17604
         * FIXME: how to detect this more correctly?  add a feature define?
 
17605
         * The size of time_t is probably not an accurate guarantee of strftime
 
17606
         * supporting or not supporting a large time range.
 
17607
         */
 
17608
        if (sizeof(time_t) < 8 &&
 
17609
           (parts[DUK__IDX_YEAR] < 1970 || parts[DUK__IDX_YEAR] > 2037)) {
 
17610
                /* be paranoid for 32-bit time values (even avoiding negative ones) */
 
17611
                return 0;
 
17612
        }
 
17613
 
 
17614
        DUK_MEMZERO(&tm, sizeof(tm));
 
17615
        tm.tm_sec = parts[DUK__IDX_SECOND];
 
17616
        tm.tm_min = parts[DUK__IDX_MINUTE];
 
17617
        tm.tm_hour = parts[DUK__IDX_HOUR];
 
17618
        tm.tm_mday = parts[DUK__IDX_DAY];       /* already one-based */
 
17619
        tm.tm_mon = parts[DUK__IDX_MONTH] - 1;  /* one-based -> zero-based */
 
17620
        tm.tm_year = parts[DUK__IDX_YEAR] - 1900;
 
17621
        tm.tm_wday = parts[DUK__IDX_WEEKDAY];
 
17622
        tm.tm_isdst = 0;
 
17623
 
 
17624
        DUK_MEMZERO(buf, sizeof(buf));
 
17625
        if ((flags & DUK__FLAG_TOSTRING_DATE) && (flags & DUK__FLAG_TOSTRING_TIME)) {
 
17626
                fmt = "%c";
 
17627
        } else if (flags & DUK__FLAG_TOSTRING_DATE) {
 
17628
                fmt = "%x";
 
17629
        } else {
 
17630
                DUK_ASSERT(flags & DUK__FLAG_TOSTRING_TIME);
 
17631
                fmt = "%X";
 
17632
        }
 
17633
        (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
 
17634
        DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
 
17635
 
 
17636
        duk_push_string(ctx, buf);
 
17637
        return 1;
 
17638
}
 
17639
#endif  /* DUK_USE_DATE_FMT_STRFTIME */
 
17640
 
 
17641
/*
 
17642
 *  ISO 8601 subset parser.
 
17643
 */
 
17644
 
 
17645
/* Parser part count. */
 
17646
#define DUK__NUM_ISO8601_PARSER_PARTS  9
 
17647
 
 
17648
/* Parser part indices. */
 
17649
#define DUK__PI_YEAR         0
 
17650
#define DUK__PI_MONTH        1
 
17651
#define DUK__PI_DAY          2
 
17652
#define DUK__PI_HOUR         3
 
17653
#define DUK__PI_MINUTE       4
 
17654
#define DUK__PI_SECOND       5
 
17655
#define DUK__PI_MILLISECOND  6
 
17656
#define DUK__PI_TZHOUR       7
 
17657
#define DUK__PI_TZMINUTE     8
 
17658
 
 
17659
/* Parser part masks. */
 
17660
#define DUK__PM_YEAR         (1 << DUK__PI_YEAR)
 
17661
#define DUK__PM_MONTH        (1 << DUK__PI_MONTH)
 
17662
#define DUK__PM_DAY          (1 << DUK__PI_DAY)
 
17663
#define DUK__PM_HOUR         (1 << DUK__PI_HOUR)
 
17664
#define DUK__PM_MINUTE       (1 << DUK__PI_MINUTE)
 
17665
#define DUK__PM_SECOND       (1 << DUK__PI_SECOND)
 
17666
#define DUK__PM_MILLISECOND  (1 << DUK__PI_MILLISECOND)
 
17667
#define DUK__PM_TZHOUR       (1 << DUK__PI_TZHOUR)
 
17668
#define DUK__PM_TZMINUTE     (1 << DUK__PI_TZMINUTE)
 
17669
 
 
17670
/* Parser separator indices. */
 
17671
#define DUK__SI_PLUS         0
 
17672
#define DUK__SI_MINUS        1
 
17673
#define DUK__SI_T            2
 
17674
#define DUK__SI_SPACE        3
 
17675
#define DUK__SI_COLON        4
 
17676
#define DUK__SI_PERIOD       5
 
17677
#define DUK__SI_Z            6
 
17678
#define DUK__SI_NUL          7
 
17679
 
 
17680
/* Parser separator masks. */
 
17681
#define DUK__SM_PLUS         (1 << DUK__SI_PLUS)
 
17682
#define DUK__SM_MINUS        (1 << DUK__SI_MINUS)
 
17683
#define DUK__SM_T            (1 << DUK__SI_T)
 
17684
#define DUK__SM_SPACE        (1 << DUK__SI_SPACE)
 
17685
#define DUK__SM_COLON        (1 << DUK__SI_COLON)
 
17686
#define DUK__SM_PERIOD       (1 << DUK__SI_PERIOD)
 
17687
#define DUK__SM_Z            (1 << DUK__SI_Z)
 
17688
#define DUK__SM_NUL          (1 << DUK__SI_NUL)
 
17689
 
 
17690
/* Rule control flags. */
 
17691
#define DUK__CF_NEG          (1 << 0)  /* continue matching, set neg_tzoffset flag */
 
17692
#define DUK__CF_ACCEPT       (1 << 1)  /* accept string */
 
17693
#define DUK__CF_ACCEPT_NUL   (1 << 2)  /* accept string if next char is NUL (otherwise reject) */
 
17694
 
 
17695
#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags)  \
 
17696
        ((partmask) + ((sepmask) << 9) + ((nextpart) << 17) + ((flags) << 21))
 
17697
 
 
17698
#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags)  do { \
 
17699
                (var_nextidx) = ((rule) >> 17) & 0x0f; \
 
17700
                (var_flags) = (rule) >> 21; \
 
17701
        } while (0)
 
17702
 
 
17703
#define DUK__RULE_MASK_PART_SEP  0x1ffff
 
17704
 
 
17705
/* Matching separator index is used in the control table */
 
17706
static const char duk__parse_iso8601_seps[] = {
 
17707
        '+' /*0*/, '-' /*1*/, 'T' /*2*/, ' ' /*3*/,
 
17708
        ':' /*4*/, '.' /*5*/, 'Z' /*6*/, (char) 0 /*7*/
 
17709
};
 
17710
 
 
17711
/* Rule table: first matching rule is used to determine what to do next. */
 
17712
static const int duk__parse_iso8601_control[] = {
 
17713
        DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
 
17714
        DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
 
17715
        DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
 
17716
        DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
 
17717
        DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
 
17718
        DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
 
17719
        DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
 
17720
        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),
 
17721
        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),
 
17722
        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),
 
17723
        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)
 
17724
 
 
17725
        /* Note1: the specification doesn't require matching a time form with
 
17726
         *        just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
 
17727
         *
 
17728
         * Note2: the specification doesn't require matching a timezone offset
 
17729
         *        with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
 
17730
         */
 
17731
};
 
17732
 
 
17733
static int duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
 
17734
        int parts[DUK__NUM_ISO8601_PARSER_PARTS];
 
17735
        double dparts[DUK__NUM_PARTS];
 
17736
        double d;
 
17737
        const char *p;
 
17738
        int part_idx = 0;
 
17739
        int accum = 0;
 
17740
        int neg_year = 0;
 
17741
        int neg_tzoffset = 0;
 
17742
        int ndigits = 0;
 
17743
        char ch;
 
17744
        int i;
 
17745
 
 
17746
        /* During parsing, month and day are one-based; set defaults here. */
 
17747
        DUK_MEMZERO(parts, sizeof(parts));
 
17748
        DUK_ASSERT(parts[DUK__IDX_YEAR] == 0);  /* don't care value, year is mandatory */
 
17749
        parts[DUK__IDX_MONTH] = 1;
 
17750
        parts[DUK__IDX_DAY] = 1;
 
17751
 
 
17752
        /* Special handling for year sign. */
 
17753
        p = str;
 
17754
        ch = p[0];
 
17755
        if (ch == '+') {
 
17756
                p++;
 
17757
        } else if (ch == '-') {
 
17758
                neg_year = 1;
 
17759
                p++;
 
17760
        }
 
17761
 
 
17762
        for (;;) {
 
17763
                ch = *p++;
 
17764
                DUK_DDDPRINT("parsing, part_idx=%d, char=%d ('%c')", part_idx, (int) ch,
 
17765
                             (ch >= 0x20 && ch <= 0x7e) ? ch : '?');
 
17766
 
 
17767
                if (ch >= '0' && ch <= '9') {
 
17768
                        if (ndigits >= 9) {
 
17769
                                DUK_DDDPRINT("too many digits -> reject");
 
17770
                                goto reject;
 
17771
                        }
 
17772
                        if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
 
17773
                                /* ignore millisecond fractions after 3 */
 
17774
                        } else {
 
17775
                                accum = accum * 10 + ((int) ch) - ((int) '0') + 0x00;
 
17776
                                ndigits++;
 
17777
                        }
 
17778
                } else {
 
17779
                        int match_val;
 
17780
                        int sep_idx;
 
17781
 
 
17782
                        if (ndigits <= 0) {
 
17783
                                goto reject;
 
17784
                        }
 
17785
                        if (part_idx == DUK__PI_MILLISECOND) {
 
17786
                                /* complete the millisecond field */
 
17787
                                while (ndigits < 3) {
 
17788
                                        accum *= 10;
 
17789
                                        ndigits++;
 
17790
                                }
 
17791
                        }
 
17792
                        parts[part_idx] = accum;
 
17793
                        DUK_DDDPRINT("wrote part %d -> value %d", part_idx, accum);
 
17794
 
 
17795
                        accum = 0;
 
17796
                        ndigits = 0;
 
17797
 
 
17798
                        for (i = 0; i < (int) sizeof(duk__parse_iso8601_seps); i++) {
 
17799
                                if (duk__parse_iso8601_seps[i] == ch) {
 
17800
                                        break;
 
17801
                                }
 
17802
                        }
 
17803
                        if (i == (int) sizeof(duk__parse_iso8601_seps)) {
 
17804
                                DUK_DDDPRINT("separator character doesn't match -> reject");
 
17805
                                goto reject;
 
17806
                        }
 
17807
 
 
17808
                        sep_idx = i;
 
17809
                        match_val = (1 << part_idx) + (1 << (sep_idx + 9));  /* match against rule part/sep bits */
 
17810
 
 
17811
                        for (i = 0; i < (int) (sizeof(duk__parse_iso8601_control) / sizeof(int)); i++) {
 
17812
                                int rule = duk__parse_iso8601_control[i];
 
17813
                                int nextpart;
 
17814
                                int cflags;
 
17815
 
 
17816
                                DUK_DDDPRINT("part_idx=%d, sep_idx=%d, match_val=0x%08x, considering rule=0x%08x",
 
17817
                                           part_idx, sep_idx, match_val, rule);
 
17818
 
 
17819
                                if ((rule & match_val) != match_val) {
 
17820
                                        continue;
 
17821
                                }
 
17822
 
 
17823
                                DUK__UNPACK_RULE(rule, nextpart, cflags);
 
17824
 
 
17825
                                DUK_DDDPRINT("rule match -> part_idx=%d, sep_idx=%d, match_val=0x%08x, rule=0x%08x -> nextpart=%d, cflags=0x%02x",
 
17826
                                             part_idx, sep_idx, match_val, rule, nextpart, cflags);
 
17827
 
 
17828
                                if (cflags & DUK__CF_NEG) {
 
17829
                                        neg_tzoffset = 1;
 
17830
                                }
 
17831
 
 
17832
                                if (cflags & DUK__CF_ACCEPT) {
 
17833
                                        goto accept;
 
17834
                                }
 
17835
 
 
17836
                                if (cflags & DUK__CF_ACCEPT_NUL) {
 
17837
                                        DUK_ASSERT(*(p-1) != (char) 0);
 
17838
                                        if (*p == '\0') {
 
17839
                                                goto accept;
 
17840
                                        }
 
17841
                                        goto reject;
 
17842
                                }
 
17843
 
 
17844
                                part_idx = nextpart;
 
17845
                                break;
 
17846
                        }  /* rule match */
 
17847
 
 
17848
                        if (i == (int) (sizeof(duk__parse_iso8601_control) / sizeof(int))) {
 
17849
                                DUK_DDDPRINT("no rule matches -> reject");
 
17850
                                goto reject;
 
17851
                        }
 
17852
 
 
17853
                        if (ch == (char) 0) {
 
17854
                                /* This shouldn't be necessary, but check just in case
 
17855
                                 * to avoid any chance of overruns.
 
17856
                                 */
 
17857
                                DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject");
 
17858
                                goto reject;
 
17859
                        }
 
17860
                }  /* if-digit-else-ctrl */
 
17861
        }  /* char loop */
 
17862
 
 
17863
        /* We should never exit the loop above, but if we do, reject
 
17864
         * by falling through.
 
17865
         */
 
17866
        DUK_DDDPRINT("fell out of char loop without explicit accept/reject -> reject");
 
17867
 
 
17868
 reject:
 
17869
        DUK_DDDPRINT("reject");
 
17870
        return 0;
 
17871
 
 
17872
 accept:
 
17873
        DUK_DDDPRINT("accept");
 
17874
 
 
17875
        /* Apply timezone offset to get the main parts in UTC */
 
17876
        if (neg_year) {
 
17877
                parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
 
17878
        }
 
17879
        if (neg_tzoffset) {
 
17880
                parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
 
17881
                parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
 
17882
        } else {
 
17883
                parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
 
17884
                parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
 
17885
        }
 
17886
        parts[DUK__PI_MONTH] -= 1;  /* zero-based month */
 
17887
        parts[DUK__PI_DAY] -= 1;  /* zero-based day */
 
17888
 
 
17889
        /* Use double parts, they tolerate unnormalized time.
 
17890
         *
 
17891
         * Note: DUK__IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
 
17892
         * on purpose.  It won't be actually used by duk__get_timeval_from_dparts(),
 
17893
         * but will make the value initialized just in case, and avoid any
 
17894
         * potential for Valgrind issues.
 
17895
         */
 
17896
        for (i = 0; i < DUK__NUM_PARTS; i++) {
 
17897
                DUK_DDDPRINT("part[%d] = %d", i, parts[i]);
 
17898
                dparts[i] = parts[i];
 
17899
        }
 
17900
 
 
17901
        d = duk__get_timeval_from_dparts(dparts, 0 /*flags*/);
 
17902
        duk_push_number(ctx, d);
 
17903
        return 1;
 
17904
}
 
17905
 
 
17906
/*
 
17907
 *  Date/time parsing helper.
 
17908
 *
 
17909
 *  Parse a datetime string into a time value.  We must first try to parse
 
17910
 *  the input according to the standard format in E5.1 Section 15.9.1.15.
 
17911
 *  If that fails, we can try to parse using custom parsing, which can
 
17912
 *  either be platform neutral (custom code) or platform specific (using
 
17913
 *  existing platform API calls).
 
17914
 *
 
17915
 *  Note in particular that we must parse whatever toString(), toUTCString(),
 
17916
 *  and toISOString() can produce; see E5.1 Section 15.9.4.2.
 
17917
 */
 
17918
 
 
17919
/*
 
17920
 *  FIXME: check standard behavior and also usual behavior in other
 
17921
 *  implementations.  For instance, V8 parses '2012-01-01' as UTC and
 
17922
 *  '2012/01/01' as local time.
 
17923
 */
 
17924
 
 
17925
static int duk__parse_string(duk_context *ctx, const char *str) {
 
17926
        /* XXX: there is a small risk here: because the ISO 8601 parser is
 
17927
         * very loose, it may end up parsing some datetime values which
 
17928
         * would be better parsed with a platform specific parser.
 
17929
         */
 
17930
 
 
17931
        DUK_ASSERT(str != NULL);
 
17932
        DUK_DDDPRINT("parse datetime from string '%s'", str);
 
17933
 
 
17934
        if (duk__parse_string_iso8601_subset(ctx, str) > 0) {
 
17935
                return 1;
 
17936
        }
 
17937
 
 
17938
#if defined(DUK_USE_DATE_PRS_STRPTIME)
 
17939
        if (duk__parse_string_strptime(ctx, str) > 0) {
 
17940
                return 1;
 
17941
        }
 
17942
#elif defined(DUK_USE_DATE_PRS_GETDATE)
 
17943
        if (duk__parse_string_getdate(ctx, str) > 0) {
 
17944
                return 1;
 
17945
        }
 
17946
#else
 
17947
        /* No platform-specific parsing, this is not an error. */
 
17948
#endif
 
17949
 
 
17950
        duk_push_nan(ctx);
 
17951
        return 1;
 
17952
}
 
17953
 
 
17954
/*
 
17955
 *  Calendar helpers
 
17956
 *
 
17957
 *  Some helpers are used for getters and can operate on normalized values
 
17958
 *  which can be represented with 32-bit signed integers.  Other helpers are
 
17959
 *  needed by setters and operate on un-normalized double values, must watch
 
17960
 *  out for non-finite numbers etc.
 
17961
 */
 
17962
 
 
17963
static unsigned char duk__days_in_month[12] = {
 
17964
        (unsigned char) 31, (unsigned char) 28, (unsigned char) 31, (unsigned char) 30,
 
17965
        (unsigned char) 31, (unsigned char) 30, (unsigned char) 31, (unsigned char) 31,
 
17966
        (unsigned char) 30, (unsigned char) 31, (unsigned char) 30, (unsigned char) 31
 
17967
};
 
17968
 
 
17969
static int duk__is_leap_year(int year) {
 
17970
        if ((year % 4) != 0) {
 
17971
                return 0;
 
17972
        }
 
17973
        if ((year % 100) != 0) {
 
17974
                return 1;
 
17975
        }
 
17976
        if ((year % 400) != 0) {
 
17977
                return 0;
 
17978
        }
 
17979
        return 1;
 
17980
}
 
17981
 
 
17982
static double duk__timeclip(double x) {
 
17983
        if (!DUK_ISFINITE(x)) {
 
17984
                return DUK_DOUBLE_NAN;
 
17985
        }
 
17986
 
 
17987
        if (x > 8.64e15 || x < -8.64e15) {
 
17988
                return DUK_DOUBLE_NAN;
 
17989
        }
 
17990
 
 
17991
        x = duk_js_tointeger_number(x);
 
17992
 
 
17993
        /* Here we'd have the option to normalize -0 to +0. */
 
17994
        return x;
 
17995
}
 
17996
 
 
17997
/* Integer division which floors also negative values correctly. */
 
17998
static int duk__div_floor(int a, int b) {
 
17999
        DUK_ASSERT(b > 0);
 
18000
        if (a >= 0) {
 
18001
                return a / b;
 
18002
        } else {
 
18003
                /* e.g. a = -4, b = 5  -->  -4 - 5 + 1 / 5  -->  -8 / 5  -->  -1
 
18004
                 *      a = -5, b = 5  -->  -5 - 5 + 1 / 5  -->  -9 / 5  -->  -1
 
18005
                 *      a = -6, b = 5  -->  -6 - 5 + 1 / 5  -->  -10 / 5  -->  -2
 
18006
                 */
 
18007
                return (a - b + 1) / b;
 
18008
        }
 
18009
}
 
18010
 
 
18011
/* Compute day number of the first day of a given year. */
 
18012
static int duk__day_from_year(int year) {
 
18013
        /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
 
18014
         * values, but is incorrect for negative ones.
 
18015
         */
 
18016
        return 365 * (year - 1970) + duk__div_floor(year - 1969, 4) - duk__div_floor(year - 1901, 100) + duk__div_floor(year - 1601, 400);
 
18017
}
 
18018
 
 
18019
/* Given a day number, determine year and day-within-year. */
 
18020
static int duk__year_from_day(int day, int *out_day_within_year) {
 
18021
        int year;
 
18022
        int diff_days;
 
18023
 
 
18024
        /* estimate year upwards (towards positive infinity), then back down;
 
18025
         * two iterations should be enough
 
18026
         */
 
18027
 
 
18028
        if (day >= 0) {
 
18029
                year = 1970 + day / 365;
 
18030
        } else {
 
18031
                year = 1970 + day / 366;
 
18032
        }
 
18033
 
 
18034
        for (;;) {
 
18035
                diff_days = duk__day_from_year(year) - day;
 
18036
                DUK_DDDPRINT("year=%d day=%d, diff_days=%d", year, day, diff_days);
 
18037
                if (diff_days <= 0) {
 
18038
                        *out_day_within_year = -diff_days;
 
18039
                        DUK_DDDPRINT("--> year=%d, day-within-year=%d",
 
18040
                                     year, *out_day_within_year);
 
18041
                        DUK_ASSERT(*out_day_within_year >= 0);
 
18042
                        DUK_ASSERT(*out_day_within_year <= (duk__is_leap_year(year) ? 366 : 365));
 
18043
                        return year;
 
18044
                }
 
18045
 
 
18046
                /* Note: this is very tricky; we must never 'overshoot' the
 
18047
                 * correction downwards.
 
18048
                 */
 
18049
                year -= 1 + (diff_days - 1) / 366;  /* conservative */
 
18050
        }
 
18051
}
 
18052
 
 
18053
/* Given a (year, month, day-within-month) triple, compute day number.
 
18054
 * The input triple is un-normalized and may contain non-finite values.
 
18055
 */
 
18056
static double duk__make_day(double year, double month, double day) {
 
18057
        int day_num;
 
18058
        int is_leap;
 
18059
        int i;
 
18060
 
 
18061
        /* Assume that year, month, day are all coerced to whole numbers.
 
18062
         * They may also be NaN or infinity, in which case this function
 
18063
         * must return NaN or infinity to ensure time value becomes NaN.
 
18064
         */
 
18065
 
 
18066
        if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
 
18067
                return DUK_DOUBLE_NAN;
 
18068
        }
 
18069
        
 
18070
        year += DUK_FLOOR(month / 12);
 
18071
 
 
18072
        month = DUK_FMOD(month, 12);
 
18073
        if (month < 0) {
 
18074
                /* handle negative values */
 
18075
                month += 12;
 
18076
        }
 
18077
 
 
18078
        /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
 
18079
         * does not normalize the day-of-month (nor check whether or not
 
18080
         * it is finite) because it's not necessary for finding the day
 
18081
         * number which matches the (year,month) pair.
 
18082
         *
 
18083
         * We assume that duk__day_from_year() is exact here.
 
18084
         *
 
18085
         * Without an explicit infinity / NaN check in the beginning,
 
18086
         * day_num would be a bogus integer here.
 
18087
         */
 
18088
 
 
18089
        day_num = duk__day_from_year((int) year);
 
18090
        is_leap = duk__is_leap_year((int) year);
 
18091
        for (i = 0; i < (int) month; i++) {
 
18092
                day_num += duk__days_in_month[i];
 
18093
                if (i == 1 && is_leap) {
 
18094
                        day_num++;
 
18095
                }
 
18096
        }
 
18097
 
 
18098
        return (double) day_num + day;
 
18099
}
 
18100
 
 
18101
/* Split time value into parts.  The time value is assumed to be an internal
 
18102
 * one, i.e. finite, no fractions.  Possible local time adjustment has already
 
18103
 * been applied when reading the time value.
 
18104
 */
 
18105
static void duk__timeval_to_parts(double d, int *parts, double *dparts, int flags) {
 
18106
        double d1, d2;
 
18107
        int t1, t2;
 
18108
        int year, month, day;
 
18109
        int dim;
 
18110
        int i;
 
18111
        int is_leap;
 
18112
 
 
18113
        DUK_ASSERT(DUK_ISFINITE(d));    /* caller checks */
 
18114
        DUK_ASSERT(DUK_FLOOR(d) == d);  /* no fractions in internal time */
 
18115
 
 
18116
        /* these computations are guaranteed to be exact for the valid
 
18117
         * E5 time value range, assuming milliseconds without fractions.
 
18118
         */
 
18119
        d1 = DUK_FMOD(d, (double) DUK__MS_DAY);
 
18120
        if (d1 < 0.0) {
 
18121
                /* deal with negative values */
 
18122
                d1 += (double) DUK__MS_DAY;
 
18123
        }
 
18124
        d2 = DUK_FLOOR(d / (double) DUK__MS_DAY);
 
18125
        DUK_ASSERT(d2 * ((double) DUK__MS_DAY) + d1 == d);
 
18126
 
 
18127
        /* now expected to fit into a 32-bit integer */
 
18128
        t1 = (int) d1;
 
18129
        t2 = (int) d2;
 
18130
        DUK_ASSERT((double) t1 == d1);
 
18131
        DUK_ASSERT((double) t2 == d2);
 
18132
 
 
18133
        /* t1 = milliseconds within day, t2 = day number */
 
18134
 
 
18135
        parts[DUK__IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
 
18136
        parts[DUK__IDX_SECOND] = t1 % 60; t1 /= 60;
 
18137
        parts[DUK__IDX_MINUTE] = t1 % 60; t1 /= 60;
 
18138
        parts[DUK__IDX_HOUR] = t1;
 
18139
        DUK_ASSERT(parts[DUK__IDX_MILLISECOND] >= 0 && parts[DUK__IDX_MILLISECOND] <= 999);
 
18140
        DUK_ASSERT(parts[DUK__IDX_SECOND] >= 0 && parts[DUK__IDX_SECOND] <= 59);
 
18141
        DUK_ASSERT(parts[DUK__IDX_MINUTE] >= 0 && parts[DUK__IDX_MINUTE] <= 59);
 
18142
        DUK_ASSERT(parts[DUK__IDX_HOUR] >= 0 && parts[DUK__IDX_HOUR] <= 23);
 
18143
 
 
18144
        parts[DUK__IDX_WEEKDAY] = (t2 + 4) % 7;  /* E5.1 Section 15.9.1.6 */
 
18145
        if (parts[DUK__IDX_WEEKDAY] < 0) {
 
18146
                /* deal with negative values */
 
18147
                parts[DUK__IDX_WEEKDAY] += 7;
 
18148
        }
 
18149
 
 
18150
        year = duk__year_from_day(t2, &day);
 
18151
        is_leap = duk__is_leap_year(year);
 
18152
        for (month = 0; month < 12; month++) {
 
18153
                dim = duk__days_in_month[month];
 
18154
                if (month == 1 && is_leap) {
 
18155
                        dim++;
 
18156
                }
 
18157
                DUK_DDDPRINT("month=%d, dim=%d, day=%d", month, dim, day);
 
18158
                if (day < dim) {
 
18159
                        break;
 
18160
                }
 
18161
                day -= dim;
 
18162
        }
 
18163
        DUK_DDDPRINT("final month=%d", month);
 
18164
        DUK_ASSERT(month >= 0 && month <= 11);
 
18165
        DUK_ASSERT(day >= 0 && day <= 31);
 
18166
 
 
18167
        parts[DUK__IDX_YEAR] = year;
 
18168
        parts[DUK__IDX_MONTH] = month;
 
18169
        parts[DUK__IDX_DAY] = day;
 
18170
 
 
18171
        if (flags & DUK__FLAG_ONEBASED) {
 
18172
                parts[DUK__IDX_MONTH]++;  /* zero-based -> one-based */
 
18173
                parts[DUK__IDX_DAY]++;    /* -""- */
 
18174
        }
 
18175
 
 
18176
        if (dparts != NULL) {
 
18177
                for (i = 0; i < DUK__NUM_PARTS; i++) {
 
18178
                        dparts[i] = (double) parts[i];
 
18179
                }
 
18180
        }
 
18181
}
 
18182
 
 
18183
/* Compute time value from (double) parts. */
 
18184
static double duk__get_timeval_from_dparts(double *dparts, int flags) {
 
18185
        double tmp_time;
 
18186
        double tmp_day;
 
18187
        double d;
 
18188
        int i;
 
18189
 
 
18190
        /* Expects 'this' at top of stack on entry. */
 
18191
 
 
18192
        /* Coerce all finite parts with ToInteger().  ToInteger() must not
 
18193
         * be called for NaN/Infinity because it will convert e.g. NaN to
 
18194
         * zero.  If ToInteger() has already been called, this has no side
 
18195
         * effects and is idempotent.
 
18196
         *
 
18197
         * Don't read dparts[DUK__IDX_WEEKDAY]; it will cause Valgrind issues
 
18198
         * if the value is uninitialized.
 
18199
         */
 
18200
        for (i = 0; i <= DUK__IDX_MILLISECOND; i++) {
 
18201
                d = dparts[i];
 
18202
                if (DUK_ISFINITE(d)) {
 
18203
                        dparts[i] = duk_js_tointeger_number(d);
 
18204
                }
 
18205
        }
 
18206
 
 
18207
        /* Use explicit steps in computation to try to ensure that
 
18208
         * computation happens with intermediate results coerced to
 
18209
         * double values (instead of using something more accurate).
 
18210
         * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
 
18211
         * rules (= Ecmascript '+' and '*' operators).
 
18212
         */
 
18213
        
 
18214
        /* MakeTime */
 
18215
        tmp_time = 0;
 
18216
        tmp_time += dparts[DUK__IDX_HOUR] * ((double) DUK__MS_HOUR);
 
18217
        tmp_time += dparts[DUK__IDX_MINUTE] * ((double) DUK__MS_MINUTE);
 
18218
        tmp_time += dparts[DUK__IDX_SECOND] * ((double) DUK__MS_SECOND);
 
18219
        tmp_time += dparts[DUK__IDX_MILLISECOND];
 
18220
 
 
18221
        /* MakeDay */
 
18222
        tmp_day = duk__make_day(dparts[DUK__IDX_YEAR], dparts[DUK__IDX_MONTH], dparts[DUK__IDX_DAY]);
 
18223
 
 
18224
        /* MakeDate */
 
18225
        d = tmp_day * ((double) DUK__MS_DAY) + tmp_time;
 
18226
 
 
18227
        DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf", tmp_time, tmp_day, d);
 
18228
 
 
18229
        /* Optional UTC conversion followed by TimeClip().
 
18230
         * Note that this also handles Infinity -> NaN conversion.
 
18231
         */
 
18232
        if (flags & DUK__FLAG_LOCALTIME) {
 
18233
                /* FIXME: this is now incorrect.  'd' is local time here (as
 
18234
                 * we're converting to UTC), but DUK__GET_LOCAL_TZOFFSET() should
 
18235
                 * be called with UTC time.  This needs to be reworked to avoid
 
18236
                 * the chicken-and-egg problem.
 
18237
                 *
 
18238
                 * See E5.1 Section 15.9.1.9:
 
18239
                 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
 
18240
                 *
 
18241
                 * For NaN/inf, DUK__GET_LOCAL_TZOFFSET() returns 0.
 
18242
                 */
 
18243
 
 
18244
                d -= DUK__GET_LOCAL_TZOFFSET(d) * 1000;
 
18245
        }
 
18246
        d = duk__timeclip(d);
 
18247
 
 
18248
        return d;
 
18249
}
 
18250
 
 
18251
/*
 
18252
 *  API oriented helpers
 
18253
 */
 
18254
 
 
18255
/* Push 'this' binding, check that it is a Date object; then push the
 
18256
 * internal time value.  At the end, stack is: [ ... this timeval ].
 
18257
 * Returns the time value.  Local time adjustment is done if requested.
 
18258
 */
 
18259
static double duk__push_this_get_timeval_tzoffset(duk_context *ctx, int flags, int *out_tzoffset) {
 
18260
        duk_hthread *thr = (duk_hthread *) ctx;
 
18261
        duk_hobject *h;
 
18262
        double d;
 
18263
        int tzoffset = 0;
 
18264
 
 
18265
        duk_push_this(ctx);
 
18266
        h = duk_get_hobject(ctx, -1);  /* FIXME: getter with class check, useful in built-ins */
 
18267
        if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
 
18268
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "expected Date");
 
18269
        }
 
18270
 
 
18271
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
18272
        d = duk_to_number(ctx, -1);
 
18273
        duk_pop(ctx);
 
18274
 
 
18275
        if (DUK_ISNAN(d)) {
 
18276
                if (flags & DUK__FLAG_NAN_TO_ZERO) {
 
18277
                        d = 0.0;
 
18278
                }
 
18279
                if (flags & DUK__FLAG_NAN_TO_RANGE_ERROR) {
 
18280
                        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "Invalid Date");
 
18281
                }
 
18282
        }
 
18283
        /* if no NaN handling flag, may still be NaN here, but not Inf */
 
18284
        DUK_ASSERT(!DUK_ISINF(d));
 
18285
 
 
18286
        if (flags & DUK__FLAG_LOCALTIME) {
 
18287
                /* Note: DST adjustment is determined using UTC time.
 
18288
                 * If 'd' is NaN, tzoffset will be 0.
 
18289
                 */
 
18290
                tzoffset = DUK__GET_LOCAL_TZOFFSET(d);  /* seconds */
 
18291
                d += tzoffset * 1000;
 
18292
        }
 
18293
        if (out_tzoffset) {
 
18294
                *out_tzoffset = tzoffset;
 
18295
        }
 
18296
 
 
18297
        /* [ ... this ] */
 
18298
        return d;
 
18299
}
 
18300
 
 
18301
static double duk__push_this_get_timeval(duk_context *ctx, int flags) {
 
18302
        return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
 
18303
}
 
18304
 
 
18305
/* Set timeval to 'this' from dparts, push the new time value onto the
 
18306
 * value stack and return 1 (caller can then tailcall us).  Expects
 
18307
 * the value stack to contain 'this' on the stack top.
 
18308
 */
 
18309
static int duk__set_this_timeval_from_dparts(duk_context *ctx, double *dparts, int flags) {
 
18310
        double d;
 
18311
 
 
18312
        /* [ ... this ] */
 
18313
 
 
18314
        d = duk__get_timeval_from_dparts(dparts, flags);
 
18315
        duk_push_number(ctx, d);  /* -> [ ... this timeval_new ] */
 
18316
        duk_dup_top(ctx);         /* -> [ ... this timeval_new timeval_new ] */
 
18317
        duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
 
18318
 
 
18319
        /* stack top: new time value */
 
18320
        return 1;
 
18321
}
 
18322
 
 
18323
/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
 
18324
static void duk__format_parts_iso8601(int *parts, int tzoffset, int flags, duk_uint8_t *out_buf) {
 
18325
        char yearstr[8];   /* "-123456\0" */
 
18326
        char tzstr[8];     /* "+11:22\0" */
 
18327
        char sep = (flags & DUK__FLAG_SEP_T) ? 'T' : ' ';
 
18328
 
 
18329
        DUK_ASSERT(parts[DUK__IDX_MONTH] >= 1 && parts[DUK__IDX_MONTH] <= 12);
 
18330
        DUK_ASSERT(parts[DUK__IDX_DAY] >= 1 && parts[DUK__IDX_DAY] <= 31);
 
18331
        DUK_ASSERT(parts[DUK__IDX_YEAR] >= -999999 && parts[DUK__IDX_YEAR] <= 999999);
 
18332
 
 
18333
        /* Note: %06d for positive value, %07d for negative value to include
 
18334
         * sign and 6 digits.
 
18335
         */
 
18336
        DUK_SNPRINTF(yearstr,
 
18337
                     sizeof(yearstr),
 
18338
                     (parts[DUK__IDX_YEAR] >= 0 && parts[DUK__IDX_YEAR] <= 9999) ? "%04d" :
 
18339
                            ((parts[DUK__IDX_YEAR] >= 0) ? "+%06d" : "%07d"),
 
18340
                     parts[DUK__IDX_YEAR]);
 
18341
        yearstr[sizeof(yearstr) - 1] = (char) 0;
 
18342
 
 
18343
        if (flags & DUK__FLAG_LOCALTIME) {
 
18344
                /* tzoffset seconds are dropped */
 
18345
                if (tzoffset >= 0) {
 
18346
                        int tmp = tzoffset / 60;
 
18347
                        DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", tmp / 60, tmp % 60);
 
18348
                } else {
 
18349
                        int tmp = -tzoffset / 60;
 
18350
                        DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", tmp / 60, tmp % 60);
 
18351
                }
 
18352
                tzstr[sizeof(tzstr) - 1] = (char) 0;
 
18353
        } else {
 
18354
                tzstr[0] = 'Z';
 
18355
                tzstr[1] = (char) 0;
 
18356
        }
 
18357
 
 
18358
        if ((flags & DUK__FLAG_TOSTRING_DATE) && (flags & DUK__FLAG_TOSTRING_TIME)) {
 
18359
                DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
 
18360
                            yearstr, parts[DUK__IDX_MONTH], parts[DUK__IDX_DAY], sep,
 
18361
                            parts[DUK__IDX_HOUR], parts[DUK__IDX_MINUTE], parts[DUK__IDX_SECOND],
 
18362
                            parts[DUK__IDX_MILLISECOND], tzstr);
 
18363
        } else if (flags & DUK__FLAG_TOSTRING_DATE) {
 
18364
                DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d", yearstr, parts[DUK__IDX_MONTH], parts[DUK__IDX_DAY]);
 
18365
        } else {
 
18366
                DUK_ASSERT(flags & DUK__FLAG_TOSTRING_TIME);
 
18367
                DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s", parts[DUK__IDX_HOUR], parts[DUK__IDX_MINUTE],
 
18368
                            parts[DUK__IDX_SECOND], parts[DUK__IDX_MILLISECOND], tzstr);
 
18369
        }
 
18370
}
 
18371
 
 
18372
/* Helper for string conversion calls: check 'this' binding, get the
 
18373
 * internal time value, and format date and/or time in a few formats.
 
18374
 */
 
18375
static int duk__to_string_helper(duk_context *ctx, int flags) {
 
18376
        double d;
 
18377
        int parts[DUK__NUM_PARTS];
 
18378
        int tzoffset;  /* seconds */
 
18379
        int rc;
 
18380
        duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
 
18381
 
 
18382
        DUK_UNREF(rc);  /* unreferenced with some options */
 
18383
 
 
18384
        d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
 
18385
        if (DUK_ISNAN(d)) {
 
18386
                duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
 
18387
                return 1;
 
18388
        }
 
18389
        DUK_ASSERT(DUK_ISFINITE(d));
 
18390
 
 
18391
        /* formatters always get one-based month/day-of-month */
 
18392
        duk__timeval_to_parts(d, parts, NULL, DUK__FLAG_ONEBASED);
 
18393
        DUK_ASSERT(parts[DUK__IDX_MONTH] >= 1 && parts[DUK__IDX_MONTH] <= 12);
 
18394
        DUK_ASSERT(parts[DUK__IDX_DAY] >= 1 && parts[DUK__IDX_DAY] <= 31);
 
18395
 
 
18396
        if (flags & DUK__FLAG_TOSTRING_LOCALE) {
 
18397
                /* try locale specific formatter; if it refuses to format the
 
18398
                 * string, fall back to an ISO 8601 formatted value in local
 
18399
                 * time.
 
18400
                 */
 
18401
#ifdef DUK_USE_DATE_FMT_STRFTIME
 
18402
                rc = duk__format_parts_strftime(ctx, parts, tzoffset, flags);
 
18403
                if (rc == 1) {
 
18404
                        return rc;
 
18405
                }
 
18406
#else
 
18407
                /* No locale specific formatter; this is OK, we fall back
 
18408
                 * to ISO 8601.
 
18409
                 */
 
18410
#endif
 
18411
        }
 
18412
 
 
18413
        /* Different calling convention than above used because the helper
 
18414
         * is shared.
 
18415
         */
 
18416
        duk__format_parts_iso8601(parts, tzoffset, flags, buf);
 
18417
        duk_push_string(ctx, (const char *) buf);
 
18418
        return 1;
 
18419
}
 
18420
 
 
18421
/* Helper for component getter calls: check 'this' binding, get the
 
18422
 * internal time value, split it into parts (either as UTC time or
 
18423
 * local time), push a specified component as a return value to the
 
18424
 * value stack and return 1 (caller can then tailcall us).
 
18425
 */
 
18426
static int duk__get_part_helper(duk_context *ctx, int flags_and_idx) {
 
18427
        double d;
 
18428
        int parts[DUK__NUM_PARTS];
 
18429
        int idx_part = flags_and_idx >> 12;  /* unpack args */
 
18430
 
 
18431
        DUK_ASSERT(idx_part >= 0 && idx_part < DUK__NUM_PARTS);
 
18432
 
 
18433
        d = duk__push_this_get_timeval(ctx, flags_and_idx);
 
18434
        if (DUK_ISNAN(d)) {
 
18435
                duk_push_nan(ctx);
 
18436
                return 1;
 
18437
        }
 
18438
        DUK_ASSERT(DUK_ISFINITE(d));
 
18439
 
 
18440
        duk__timeval_to_parts(d, parts, NULL, flags_and_idx);
 
18441
 
 
18442
        /* Setter APIs detect special year numbers (0...99) and apply a +1900
 
18443
         * only in certain cases.  The legacy getYear() getter applies -1900
 
18444
         * unconditionally.
 
18445
         */
 
18446
        duk_push_int(ctx, (flags_and_idx & DUK__FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
 
18447
        return 1;
 
18448
}
 
18449
 
 
18450
/* Helper for component setter calls: check 'this' binding, get the
 
18451
 * internal time value, split it into parts (either as UTC time or
 
18452
 * local time), modify one or more components as specified, recompute
 
18453
 * the time value, set it as the internal value.  Finally, push the
 
18454
 * new time value as a return value to the value stack and return 1
 
18455
 * (caller can then tailcall us).
 
18456
 */
 
18457
static int duk__set_part_helper(duk_context *ctx, int flags_and_maxnargs) {
 
18458
        double d;
 
18459
        int parts[DUK__NUM_PARTS];
 
18460
        double dparts[DUK__NUM_PARTS];
 
18461
        int nargs;
 
18462
        int maxnargs = flags_and_maxnargs >> 12;  /* unpack args */
 
18463
        int idx_first, idx;
 
18464
        int i;
 
18465
 
 
18466
        nargs = duk_get_top(ctx);
 
18467
        d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
 
18468
        DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
 
18469
 
 
18470
        if (DUK_ISFINITE(d)) {
 
18471
                duk__timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
 
18472
        } else {
 
18473
                /* NaN timevalue: we need to coerce the arguments, but
 
18474
                 * the resulting internal timestamp needs to remain NaN.
 
18475
                 * This works but is not pretty: parts and dparts will
 
18476
                 * be partially uninitialized, but we only write to it.
 
18477
                 */
 
18478
        }
 
18479
 
 
18480
        /*
 
18481
         *  Determining which datetime components to overwrite based on
 
18482
         *  stack arguments is a bit complicated, but important to factor
 
18483
         *  out from setters themselves for compactness.
 
18484
         *
 
18485
         *  If DUK__FLAG_TIMESETTER, maxnargs indicates setter type:
 
18486
         *
 
18487
         *   1 -> millisecond
 
18488
         *   2 -> second, [millisecond]
 
18489
         *   3 -> minute, [second], [millisecond]
 
18490
         *   4 -> hour, [minute], [second], [millisecond]
 
18491
         *
 
18492
         *  Else:
 
18493
         *
 
18494
         *   1 -> date
 
18495
         *   2 -> month, [date]
 
18496
         *   3 -> year, [month], [date]
 
18497
         *
 
18498
         *  By comparing nargs and maxnargs (and flags) we know which
 
18499
         *  components to override.  We rely on part index ordering.
 
18500
         */
 
18501
 
 
18502
        if (flags_and_maxnargs & DUK__FLAG_TIMESETTER) {
 
18503
                DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
 
18504
                idx_first = DUK__IDX_MILLISECOND - (maxnargs - 1);
 
18505
        } else {
 
18506
                DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
 
18507
                idx_first = DUK__IDX_DAY - (maxnargs - 1);
 
18508
        }
 
18509
        DUK_ASSERT(idx_first >= 0 && idx_first < DUK__NUM_PARTS);
 
18510
 
 
18511
        for (i = 0; i < maxnargs; i++) {
 
18512
                if (i >= nargs) {
 
18513
                        /* no argument given -> leave components untouched */
 
18514
                        break;
 
18515
                }
 
18516
                idx = idx_first + i;
 
18517
                DUK_ASSERT(idx >= 0 && idx < DUK__NUM_PARTS);
 
18518
 
 
18519
                if (idx == DUK__IDX_YEAR && (flags_and_maxnargs & DUK__FLAG_YEAR_FIXUP)) {
 
18520
                        duk__twodigit_year_fixup(ctx, i);
 
18521
                }
 
18522
 
 
18523
                dparts[idx] = duk_to_number(ctx, i);
 
18524
 
 
18525
                if (idx == DUK__IDX_DAY) {
 
18526
                        /* Day-of-month is one-based in the API, but zero-based
 
18527
                         * internally, so fix here.  Note that month is zero-based
 
18528
                         * both in the API and internally.
 
18529
                         */
 
18530
                        dparts[idx] -= 1.0;
 
18531
                }
 
18532
        }
 
18533
 
 
18534
        /* Leaves new timevalue on stack top and returns 1, which is correct
 
18535
         * for part setters.
 
18536
         */
 
18537
        if (DUK_ISFINITE(d)) {
 
18538
                return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
 
18539
        } else {
 
18540
                /* Internal timevalue is already NaN, so don't touch it. */
 
18541
                duk_push_nan(ctx);
 
18542
                return 1;
 
18543
        }
 
18544
}
 
18545
 
 
18546
/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
 
18547
 * 1900 and replace value at idx_val.
 
18548
 */
 
18549
static void duk__twodigit_year_fixup(duk_context *ctx, int idx_val) {
 
18550
        double d;
 
18551
 
 
18552
        /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
 
18553
        duk_to_number(ctx, idx_val);
 
18554
        if (duk_is_nan(ctx, idx_val)) {
 
18555
                return;
 
18556
        }
 
18557
        duk_dup(ctx, idx_val);
 
18558
        duk_to_int(ctx, -1);
 
18559
        d = duk_get_number(ctx, -1);  /* get as double to handle huge numbers correctly */
 
18560
        if (d >= 0.0 && d <= 99.0) {
 
18561
                d += 1900.0;
 
18562
                duk_push_number(ctx, d);
 
18563
                duk_replace(ctx, idx_val);
 
18564
        }
 
18565
        duk_pop(ctx);
 
18566
}
 
18567
 
 
18568
/* Set datetime parts from stack arguments, defaulting any missing values.
 
18569
 * Day-of-week is not set; it is not required when setting the time value.
 
18570
 */
 
18571
static void duk__set_parts_from_args(duk_context *ctx, double *dparts, int nargs) {
 
18572
        double d;
 
18573
        int i;
 
18574
        int idx;
 
18575
 
 
18576
        /* Causes a ToNumber() coercion, but doesn't break coercion order since
 
18577
         * year is coerced first anyway.
 
18578
         */
 
18579
        duk__twodigit_year_fixup(ctx, 0);
 
18580
 
 
18581
        /* There are at most 7 args, but we use 8 here so that also
 
18582
         * DUK__IDX_WEEKDAY gets initialized (to zero) to avoid the potential
 
18583
         * for any Valgrind gripes later.
 
18584
         */
 
18585
        for (i = 0; i < 8; i++) {
 
18586
                /* Note: rely on index ordering */
 
18587
                idx = DUK__IDX_YEAR + i;
 
18588
                if (i < nargs) {
 
18589
                        d = duk_to_number(ctx, i);
 
18590
                        if (idx == DUK__IDX_DAY) {
 
18591
                                /* Convert day from one-based to zero-based (internal).  This may
 
18592
                                 * cause the day part to be negative, which is OK.
 
18593
                                 */
 
18594
                                d -= 1.0;
 
18595
                        }
 
18596
                } else {
 
18597
                        /* All components default to 0 except day-of-month which defaults
 
18598
                         * to 1.  However, because our internal day-of-month is zero-based,
 
18599
                         * it also defaults to zero here.
 
18600
                         */
 
18601
                        d = 0.0;
 
18602
                }
 
18603
                dparts[idx] = d;
 
18604
        }
 
18605
 
 
18606
        DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
 
18607
                     dparts[0], dparts[1], dparts[2], dparts[3],
 
18608
                     dparts[4], dparts[5], dparts[6], dparts[7]);
 
18609
}
 
18610
 
 
18611
/*
 
18612
 *  Helper to format a time value into caller buffer, used by logging.
 
18613
 *  'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
 
18614
 */
 
18615
 
 
18616
void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
 
18617
        int parts[DUK__NUM_PARTS];
 
18618
 
 
18619
        duk__timeval_to_parts(timeval,
 
18620
                              parts,
 
18621
                              NULL,
 
18622
                              DUK__FLAG_ONEBASED);
 
18623
 
 
18624
        duk__format_parts_iso8601(parts,
 
18625
                                  0 /*tzoffset*/,
 
18626
                                  DUK__FLAG_TOSTRING_DATE |
 
18627
                                  DUK__FLAG_TOSTRING_TIME |
 
18628
                                  DUK__FLAG_SEP_T /*flags*/,
 
18629
                                  out_buf);
 
18630
}
 
18631
 
 
18632
/*
 
18633
 *  Constructor calls
 
18634
 */
 
18635
 
 
18636
int duk_bi_date_constructor(duk_context *ctx) {
 
18637
        int nargs = duk_get_top(ctx);
 
18638
        int is_cons = duk_is_constructor_call(ctx);
 
18639
        double dparts[DUK__NUM_PARTS];
 
18640
        double d;
 
18641
 
 
18642
        DUK_DDDPRINT("Date constructor, nargs=%d, is_cons=%d", nargs, is_cons);
 
18643
 
 
18644
        duk_push_object_helper(ctx,
 
18645
                               DUK_HOBJECT_FLAG_EXTENSIBLE |
 
18646
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
 
18647
                               DUK_BIDX_DATE_PROTOTYPE);
 
18648
 
 
18649
        /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
 
18650
         * is mutable.
 
18651
         */
 
18652
 
 
18653
        if (nargs == 0 || !is_cons) {
 
18654
                d = duk__timeclip(DUK__GET_NOW_TIMEVAL(ctx));
 
18655
                duk_push_number(ctx, d);
 
18656
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
 
18657
                if (!is_cons) {
 
18658
                        /* called as a normal function: return new Date().toString() */
 
18659
                        duk_to_string(ctx, -1);
 
18660
                }
 
18661
                return 1;
 
18662
        } else if (nargs == 1) {
 
18663
                duk_to_primitive(ctx, 0, DUK_HINT_NONE);
 
18664
                if (duk_is_string(ctx, 0)) {
 
18665
                        duk__parse_string(ctx, duk_to_string(ctx, 0));
 
18666
                        duk_replace(ctx, 0);  /* may be NaN */
 
18667
                }
 
18668
                d = duk__timeclip(duk_to_number(ctx, 0));
 
18669
                duk_push_number(ctx, d);
 
18670
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
 
18671
                return 1;
 
18672
        }
 
18673
 
 
18674
        duk__set_parts_from_args(ctx, dparts, nargs);
 
18675
 
 
18676
        /* Parts are in local time, convert when setting. */
 
18677
 
 
18678
        duk__set_this_timeval_from_dparts(ctx, dparts, DUK__FLAG_LOCALTIME /*flags*/);  /* -> [ ... this timeval ] */
 
18679
        duk_pop(ctx);  /* -> [ ... this ] */
 
18680
        return 1;
 
18681
}
 
18682
 
 
18683
int duk_bi_date_constructor_parse(duk_context *ctx) {
 
18684
        return duk__parse_string(ctx, duk_to_string(ctx, 0));
 
18685
}
 
18686
 
 
18687
int duk_bi_date_constructor_utc(duk_context *ctx) {
 
18688
        int nargs = duk_get_top(ctx);
 
18689
        double dparts[DUK__NUM_PARTS];
 
18690
        double d;
 
18691
 
 
18692
        /* Behavior for nargs < 2 is implementation dependent: currently we'll
 
18693
         * set a NaN time value (matching V8 behavior) in this case.
 
18694
         */
 
18695
 
 
18696
        if (nargs < 2) {
 
18697
                duk_push_nan(ctx);
 
18698
        } else {
 
18699
                duk__set_parts_from_args(ctx, dparts, nargs);
 
18700
                d = duk__get_timeval_from_dparts(dparts, 0 /*flags*/);
 
18701
                duk_push_number(ctx, d);
 
18702
        }
 
18703
        return 1;
 
18704
}
 
18705
 
 
18706
int duk_bi_date_constructor_now(duk_context *ctx) {
 
18707
        double d;
 
18708
 
 
18709
        d = DUK__GET_NOW_TIMEVAL(ctx);
 
18710
        DUK_ASSERT(duk__timeclip(d) == d);  /* TimeClip() should never be necessary */
 
18711
        duk_push_number(ctx, d);
 
18712
        return 1;
 
18713
}
 
18714
 
 
18715
/*
 
18716
 *  String/JSON conversions
 
18717
 *
 
18718
 *  Human readable conversions are now basically ISO 8601 with a space
 
18719
 *  (instead of 'T') as the date/time separator.  This is a good baseline
 
18720
 *  and is platform independent.
 
18721
 *
 
18722
 *  A shared native helper to provide many conversions.  Magic value contains
 
18723
 *  a set of flags.  The helper provides:
 
18724
 *
 
18725
 *    toString()
 
18726
 *    toDateString()
 
18727
 *    toTimeString()
 
18728
 *    toLocaleString()
 
18729
 *    toLocaleDateString()
 
18730
 *    toLocaleTimeString()
 
18731
 *    toUTCString()
 
18732
 *    toISOString()
 
18733
 *
 
18734
 *  Notes:
 
18735
 *
 
18736
 *    - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
 
18737
 *      required to be the same Ecmascript function object (!), so it is
 
18738
 *      omitted from here.
 
18739
 *
 
18740
 *    - Date.prototype.toUTCString(): E5.1 specification does not require a
 
18741
 *      specific format, but result should be human readable.  The
 
18742
 *      specification suggests using ISO 8601 format with a space (instead
 
18743
 *      of 'T') separator if a more human readable format is not available.
 
18744
 *
 
18745
 *    - Date.prototype.toISOString(): unlike other conversion functions,
 
18746
 *      toISOString() requires a RangeError for invalid date values.
 
18747
 */
 
18748
 
 
18749
int duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
 
18750
        int flags = duk_get_magic(ctx);
 
18751
        return duk__to_string_helper(ctx, flags);
 
18752
}
 
18753
 
 
18754
int duk_bi_date_prototype_value_of(duk_context *ctx) {
 
18755
        /* This native function is also used for Date.prototype.getTime()
 
18756
         * as their behavior is identical.
 
18757
         */
 
18758
 
 
18759
        double d = duk__push_this_get_timeval(ctx, 0 /*flags*/);  /* -> [ this ] */
 
18760
        DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
 
18761
        duk_push_number(ctx, d);
 
18762
        return 1;
 
18763
}
 
18764
 
 
18765
int duk_bi_date_prototype_to_json(duk_context *ctx) {
 
18766
        /* Note: toJSON() is a generic function which works even if 'this'
 
18767
         * is not a Date.  The sole argument is ignored.
 
18768
         */
 
18769
 
 
18770
        duk_push_this(ctx);
 
18771
        duk_to_object(ctx, -1);
 
18772
 
 
18773
        duk_dup_top(ctx);
 
18774
        duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
 
18775
        if (duk_is_number(ctx, -1)) {
 
18776
                double d = duk_get_number(ctx, -1);
 
18777
                if (!DUK_ISFINITE(d)) {
 
18778
                        duk_push_null(ctx);
 
18779
                        return 1;
 
18780
                }
 
18781
        }
 
18782
        duk_pop(ctx);
 
18783
 
 
18784
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
 
18785
        duk_dup(ctx, -2);  /* -> [ O toIsoString O ] */
 
18786
        duk_call_method(ctx, 0);
 
18787
        return 1;
 
18788
}
 
18789
 
 
18790
/*
 
18791
 *  Getters.
 
18792
 *
 
18793
 *  Implementing getters is quite easy.  The internal time value is either
 
18794
 *  NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
 
18795
 *  The internal time value can be converted to integer parts, and each
 
18796
 *  part will be normalized and will fit into a 32-bit signed integer.
 
18797
 *
 
18798
 *  A shared native helper to provide all getters.  Magic value contains
 
18799
 *  a set of flags and also packs the date component index argument.  The
 
18800
 *  helper provides:
 
18801
 *
 
18802
 *    getFullYear()
 
18803
 *    getUTCFullYear()
 
18804
 *    getMonth()
 
18805
 *    getUTCMonth()
 
18806
 *    getDate()
 
18807
 *    getUTCDate()
 
18808
 *    getDay()
 
18809
 *    getUTCDay()
 
18810
 *    getHours()
 
18811
 *    getUTCHours()
 
18812
 *    getMinutes()
 
18813
 *    getUTCMinutes()
 
18814
 *    getSeconds()
 
18815
 *    getUTCSeconds()
 
18816
 *    getMilliseconds()
 
18817
 *    getUTCMilliseconds()
 
18818
 *    getYear()
 
18819
 *
 
18820
 *  Notes:
 
18821
 *
 
18822
 *    - Date.prototype.getDate(): 'date' means day-of-month, and is
 
18823
 *      zero-based in internal calculations but public API expects it to
 
18824
 *      be one-based.
 
18825
 *
 
18826
 *    - Date.prototype.getTime() and Date.prototype.valueOf() have identical
 
18827
 *      behavior.  They have separate function objects, but share the same C
 
18828
 *      function (duk_bi_date_prototype_value_of).
 
18829
 */
 
18830
 
 
18831
int duk_bi_date_prototype_get_shared(duk_context *ctx) {
 
18832
        int flags_and_idx = duk_get_magic(ctx);
 
18833
        return duk__get_part_helper(ctx, flags_and_idx);
 
18834
}
 
18835
 
 
18836
int duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
 
18837
        /*
 
18838
         *  Return (t - LocalTime(t)) in minutes:
 
18839
         *
 
18840
         *    t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
 
18841
         *                     = -(LocalTZA + DaylightSavingTA(t))
 
18842
         *
 
18843
         *  where DaylightSavingTA() is checked for time 't'.
 
18844
         *
 
18845
         *  Note that the sign of the result is opposite to common usage,
 
18846
         *  e.g. for EE(S)T which normally is +2h or +3h from UTC, this
 
18847
         *  function returns -120 or -180.
 
18848
         *
 
18849
         */
 
18850
 
 
18851
        double d;
 
18852
        int tzoffset;
 
18853
 
 
18854
        /* Note: DST adjustment is determined using UTC time. */
 
18855
        d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
 
18856
        DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
 
18857
        if (DUK_ISNAN(d)) {
 
18858
                duk_push_nan(ctx);
 
18859
        } else {
 
18860
                DUK_ASSERT(DUK_ISFINITE(d));
 
18861
                tzoffset = DUK__GET_LOCAL_TZOFFSET(d);
 
18862
                duk_push_int(ctx, -tzoffset / 60);
 
18863
        }
 
18864
        return 1;
 
18865
}
 
18866
 
 
18867
/*
 
18868
 *  Setters.
 
18869
 *
 
18870
 *  Setters are a bit more complicated than getters.  Component setters
 
18871
 *  break down the current time value into its (normalized) component
 
18872
 *  parts, replace one or more components with -unnormalized- new values,
 
18873
 *  and the components are then converted back into a time value.  As an
 
18874
 *  example of using unnormalized values:
 
18875
 *
 
18876
 *    var d = new Date(1234567890);
 
18877
 *
 
18878
 *  is equivalent to:
 
18879
 *
 
18880
 *    var d = new Date(0);
 
18881
 *    d.setUTCMilliseconds(1234567890);
 
18882
 *
 
18883
 *  A shared native helper to provide almost all setters.  Magic value
 
18884
 *  contains a set of flags and also packs the "maxnargs" argument.  The
 
18885
 *  helper provides:
 
18886
 *
 
18887
 *    setMilliseconds()
 
18888
 *    setUTCMilliseconds()
 
18889
 *    setSeconds()
 
18890
 *    setUTCSeconds()
 
18891
 *    setMinutes()
 
18892
 *    setUTCMinutes()
 
18893
 *    setHours()
 
18894
 *    setUTCHours()
 
18895
 *    setDate()
 
18896
 *    setUTCDate()
 
18897
 *    setMonth()
 
18898
 *    setUTCMonth()
 
18899
 *    setFullYear()
 
18900
 *    setUTCFullYear()
 
18901
 *    setYear()
 
18902
 *
 
18903
 *  Notes:
 
18904
 *
 
18905
 *    - Date.prototype.setYear() (Section B addition): special year check
 
18906
 *      is omitted.  NaN / Infinity will just flow through and ultimately
 
18907
 *      result in a NaN internal time value.
 
18908
 *
 
18909
 *    - Date.prototype.setYear() does not have optional arguments for
 
18910
 *      setting month and day-in-month (like setFullYear()), but we indicate
 
18911
 *      'maxnargs' to be 3 to get the year written to the correct component
 
18912
 *      index in duk__set_part_helper().  The function has nargs == 1, so only
 
18913
 *      the year will be set regardless of actual argument count.
 
18914
 */
 
18915
 
 
18916
int duk_bi_date_prototype_set_shared(duk_context *ctx) {
 
18917
        int flags_and_maxnargs = duk_get_magic(ctx);
 
18918
        return duk__set_part_helper(ctx, flags_and_maxnargs);
 
18919
}
 
18920
 
 
18921
int duk_bi_date_prototype_set_time(duk_context *ctx) {
 
18922
        double d;
 
18923
 
 
18924
        (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
 
18925
        d = duk__timeclip(duk_to_number(ctx, 0));
 
18926
        duk_push_number(ctx, d);
 
18927
        duk_dup_top(ctx);
 
18928
        duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
 
18929
 
 
18930
        return 1;
 
18931
}
 
18932
 
 
18933
#line 1 "duk_bi_duktape.c"
 
18934
/*
 
18935
 *  Duktape built-ins
 
18936
 *
 
18937
 *  Size optimization note: it might seem that vararg multipurpose functions
 
18938
 *  like fin(), enc(), and dec() are not very size optimal, but using a single
 
18939
 *  user-visible Ecmascript function saves a lot of run-time footprint; each
 
18940
 *  Function instance takes >100 bytes.  Using a shared native helper and a
 
18941
 *  'magic' value won't save much if there are multiple Function instances
 
18942
 *  anyway.
 
18943
 */
 
18944
 
 
18945
/* include removed: duk_internal.h */
 
18946
 
 
18947
/* Raw helper to extract internal information / statistics about a value.
 
18948
 * The return values are version specific and must not expose anything
 
18949
 * that would lead to security issues (e.g. exposing compiled function
 
18950
 * 'data' buffer might be an issue).  Currently only counts and sizes and
 
18951
 * such are given so there should not be a security impact.
 
18952
 */
 
18953
duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
 
18954
        duk_tval *tv;
 
18955
        duk_heaphdr *h;
 
18956
        duk_int_t i, n;
 
18957
 
 
18958
        tv = duk_get_tval(ctx, 0);
 
18959
        DUK_ASSERT(tv != NULL);  /* because arg count is 1 */
 
18960
 
 
18961
        duk_push_array(ctx);  /* -> [ val arr ] */
 
18962
 
 
18963
        /* type tag (public) */
 
18964
        duk_push_int(ctx, duk_get_type(ctx, 0));
 
18965
 
 
18966
        /* address */
 
18967
        if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
 
18968
                h = DUK_TVAL_GET_HEAPHDR(tv);
 
18969
                duk_push_pointer(ctx, (void *) h);
 
18970
        } else {
 
18971
                goto done;
 
18972
        }
 
18973
        DUK_ASSERT(h != NULL);
 
18974
 
 
18975
        /* refcount */
 
18976
#ifdef DUK_USE_REFERENCE_COUNTING
 
18977
        duk_push_int(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
 
18978
#else
 
18979
        duk_push_undefined(ctx);
 
18980
#endif
 
18981
 
 
18982
        /* heaphdr size and additional allocation size, followed by
 
18983
         * type specific stuff (with varying value count)
 
18984
         */
 
18985
        switch (DUK_HEAPHDR_GET_TYPE(h)) {
 
18986
        case DUK_HTYPE_STRING: {
 
18987
                duk_hstring *h_str = (duk_hstring *) h;
 
18988
                duk_push_int(ctx, (int) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
 
18989
                break;
 
18990
        }
 
18991
        case DUK_HTYPE_OBJECT: {
 
18992
                duk_hobject *h_obj = (duk_hobject *) h;
 
18993
                duk_int_t hdr_size;
 
18994
                if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
 
18995
                        hdr_size = (duk_int_t) sizeof(duk_hcompiledfunction);
 
18996
                } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
 
18997
                        hdr_size = (duk_int_t) sizeof(duk_hnativefunction);
 
18998
                } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
 
18999
                        hdr_size = (duk_int_t) sizeof(duk_hthread);
 
19000
                } else {
 
19001
                        hdr_size = (duk_int_t) sizeof(duk_hobject);
 
19002
                }
 
19003
                duk_push_int(ctx, (int) hdr_size);
 
19004
                duk_push_int(ctx, (int) DUK_HOBJECT_E_ALLOC_SIZE(h_obj));
 
19005
                duk_push_int(ctx, (int) h_obj->e_size);
 
19006
                duk_push_int(ctx, (int) h_obj->e_used);
 
19007
                duk_push_int(ctx, (int) h_obj->a_size);
 
19008
                duk_push_int(ctx, (int) h_obj->h_size);
 
19009
                if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
 
19010
                        duk_hbuffer *h_data = ((duk_hcompiledfunction *) h_obj)->data;
 
19011
                        if (h_data) {
 
19012
                                duk_push_int(ctx, DUK_HBUFFER_GET_SIZE(h_data));
 
19013
                        } else {
 
19014
                                duk_push_int(ctx, 0);
 
19015
                        }
 
19016
                }
 
19017
                break;
 
19018
        }
 
19019
        case DUK_HTYPE_BUFFER: {
 
19020
                duk_hbuffer *h_buf = (duk_hbuffer *) h;
 
19021
                if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
 
19022
                        /* XXX: when usable_size == 0, dynamic buf ptr may now be NULL, in which case
 
19023
                         * the second allocation does not exist.
 
19024
                         */
 
19025
                        duk_hbuffer_dynamic *h_dyn = (duk_hbuffer_dynamic *) h;
 
19026
                        duk_push_int(ctx, (int) (sizeof(duk_hbuffer_dynamic)));
 
19027
                        duk_push_int(ctx, (int) (DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(h_dyn)));
 
19028
                } else {
 
19029
                        duk_push_int(ctx, (int) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
 
19030
                }
 
19031
                break;
 
19032
 
 
19033
        }
 
19034
        }
 
19035
 
 
19036
 done:
 
19037
        /* set values into ret array */
 
19038
        /* FIXME: primitive to make array from valstack slice */
 
19039
        n = duk_get_top(ctx);
 
19040
        for (i = 2; i < n; i++) {
 
19041
                duk_dup(ctx, i);
 
19042
                duk_put_prop_index(ctx, 1, i - 2);
 
19043
        }
 
19044
        duk_dup(ctx, 1);
 
19045
        return 1;
 
19046
}
 
19047
 
 
19048
#if defined(DUK_USE_PC2LINE)
 
19049
duk_ret_t duk_bi_duktape_object_line(duk_context *ctx) {
 
19050
        duk_hthread *thr = (duk_hthread *) ctx;
 
19051
        duk_activation *act_caller;
 
19052
        duk_hobject *h_func;
 
19053
        duk_hbuffer_fixed *pc2line;
 
19054
        duk_uint_fast32_t pc;
 
19055
        duk_uint_fast32_t line;
 
19056
 
 
19057
        if (thr->callstack_top < 2) {
 
19058
                return 0;
 
19059
        }
 
19060
        act_caller = thr->callstack + thr->callstack_top - 2;
 
19061
 
 
19062
        h_func = act_caller->func;
 
19063
        DUK_ASSERT(h_func != NULL);
 
19064
        if (!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h_func)) {
 
19065
                return 0;
 
19066
        }
 
19067
 
 
19068
        /* FIXME: shared helper */
 
19069
        duk_push_hobject(ctx, h_func);
 
19070
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_PC2LINE);
 
19071
        if (duk_is_buffer(ctx, -1)) {
 
19072
                pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
 
19073
                DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line));
 
19074
                pc = (duk_uint_fast32_t) act_caller->pc;
 
19075
                line = duk_hobject_pc2line_query(pc2line, (duk_uint_fast32_t) pc);
 
19076
        } else {
 
19077
                line = 0;
 
19078
        }
 
19079
 
 
19080
        duk_push_int(ctx, (int) line);  /* FIXME: typing */
 
19081
        return 1;
 
19082
}
 
19083
#else  /* DUK_USE_PC2LINE */
 
19084
duk_ret_t duk_bi_duktape_object_line(duk_context *ctx) {
 
19085
        DUK_UNREF(ctx);
 
19086
        return 0;
 
19087
}
 
19088
#endif  /* DUK_USE_PC2LINE */
 
19089
 
 
19090
duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
 
19091
        duk_hthread *thr = (duk_hthread *) ctx;
 
19092
        duk_activation *act;
 
19093
        duk_hobject *h_func;
 
19094
        duk_hbuffer_fixed *pc2line;
 
19095
        duk_uint_fast32_t pc;
 
19096
        duk_uint_fast32_t line;
 
19097
        duk_int_t level;
 
19098
 
 
19099
        /* -1             = top callstack entry, callstack[callstack_top - 1]
 
19100
         * -callstack_top = bottom callstack entry, callstack[0]
 
19101
         */
 
19102
        level = duk_to_int(ctx, 0);
 
19103
        if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
 
19104
                return 0;
 
19105
        }
 
19106
        DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
 
19107
        act = thr->callstack + thr->callstack_top + level;
 
19108
 
 
19109
        duk_push_object(ctx);
 
19110
 
 
19111
        h_func = act->func;
 
19112
        DUK_ASSERT(h_func != NULL);
 
19113
        duk_push_hobject(ctx, h_func);
 
19114
 
 
19115
        pc = (duk_uint_fast32_t) act->pc;
 
19116
        duk_push_int(ctx, (int) pc);  /* FIXME: typing */
 
19117
 
 
19118
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE);
 
19119
        if (duk_is_buffer(ctx, -1)) {
 
19120
                pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
 
19121
                DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line));
 
19122
                pc = (duk_uint_fast32_t) act->pc;
 
19123
                line = duk_hobject_pc2line_query(pc2line, (duk_uint_fast32_t) pc);
 
19124
        } else {
 
19125
                line = 0;
 
19126
        }
 
19127
        duk_pop(ctx);
 
19128
 
 
19129
        duk_push_int(ctx, (int) line);  /* FIXME: typing */
 
19130
 
 
19131
        /* Providing access to e.g. act->lex_env would be dangerous: these
 
19132
         * internal structures must never be accessible to the application.
 
19133
         * Duktape relies on them having consistent data, and this consistency
 
19134
         * is only asserted for, not checked for.
 
19135
         */
 
19136
 
 
19137
        /* [ level obj func pc line ] */
 
19138
 
 
19139
        /* FIXME: version specific array format instead? */
 
19140
        duk_def_prop_stridx(ctx, -4, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WEC);
 
19141
        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_PC, DUK_PROPDESC_FLAGS_WEC);
 
19142
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LC_FUNCTION, DUK_PROPDESC_FLAGS_WEC);
 
19143
        return 1;
 
19144
}
 
19145
 
 
19146
duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
 
19147
#ifdef DUK_USE_MARK_AND_SWEEP
 
19148
        duk_hthread *thr = (duk_hthread *) ctx;
 
19149
        int flags;
 
19150
        int rc;
 
19151
 
 
19152
        flags = duk_get_int(ctx, 0);
 
19153
        rc = duk_heap_mark_and_sweep(thr->heap, flags);
 
19154
        duk_push_int(ctx, rc);
 
19155
        return 1;
 
19156
#else
 
19157
        DUK_UNREF(ctx);
 
19158
        return 0;
 
19159
#endif
 
19160
}
 
19161
 
 
19162
duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
 
19163
        (void) duk_require_hobject(ctx, 0);
 
19164
        if (duk_get_top(ctx) >= 2) {
 
19165
                /* Set: currently a finalizer is disabled by setting it to
 
19166
                 * undefined; this does not remove the property at the moment.
 
19167
                 * The value could be type checked to be either a function
 
19168
                 * or something else; if something else, the property could
 
19169
                 * be deleted.
 
19170
                 */
 
19171
                duk_set_top(ctx, 2);
 
19172
                (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
 
19173
                return 0;
 
19174
        } else {
 
19175
                /* Get. */
 
19176
                DUK_ASSERT(duk_get_top(ctx) == 1);
 
19177
                duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
 
19178
                return 1;
 
19179
        }
 
19180
}
 
19181
 
 
19182
duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
 
19183
        duk_hthread *thr = (duk_hthread *) ctx;
 
19184
        duk_hstring *h_str;
 
19185
 
 
19186
        /* Vararg function: must be careful to check/require arguments.
 
19187
         * The JSON helpers accept invalid indices and treat them like
 
19188
         * non-existent optional parameters.
 
19189
         */
 
19190
 
 
19191
        h_str = duk_require_hstring(ctx, 0);
 
19192
        duk_require_valid_index(ctx, 1);
 
19193
 
 
19194
        if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
 
19195
                duk_set_top(ctx, 2);
 
19196
                duk_hex_encode(ctx, 1);
 
19197
                DUK_ASSERT_TOP(ctx, 2);
 
19198
        } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
 
19199
                duk_set_top(ctx, 2);
 
19200
                duk_base64_encode(ctx, 1);
 
19201
                DUK_ASSERT_TOP(ctx, 2);
 
19202
#ifdef DUK_USE_JSONX
 
19203
        } else if (h_str == DUK_HTHREAD_STRING_JSONX(thr)) {
 
19204
                duk_bi_json_stringify_helper(ctx,
 
19205
                                             1 /*idx_value*/,
 
19206
                                             2 /*idx_replacer*/,
 
19207
                                             3 /*idx_space*/,
 
19208
                                             DUK_JSON_FLAG_EXT_CUSTOM |
 
19209
                                             DUK_JSON_FLAG_ASCII_ONLY |
 
19210
                                             DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
 
19211
#endif
 
19212
#ifdef DUK_USE_JSONC
 
19213
        } else if (h_str == DUK_HTHREAD_STRING_JSONC(thr)) {
 
19214
                duk_bi_json_stringify_helper(ctx,
 
19215
                                             1 /*idx_value*/,
 
19216
                                             2 /*idx_replacer*/,
 
19217
                                             3 /*idx_space*/,
 
19218
                                             DUK_JSON_FLAG_EXT_COMPATIBLE |
 
19219
                                             DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
 
19220
#endif
 
19221
        } else {
 
19222
                return DUK_RET_TYPE_ERROR;
 
19223
        }
 
19224
        return 1;
 
19225
}
 
19226
 
 
19227
duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
 
19228
        duk_hthread *thr = (duk_hthread *) ctx;
 
19229
        duk_hstring *h_str;
 
19230
 
 
19231
        /* Vararg function: must be careful to check/require arguments.
 
19232
         * The JSON helpers accept invalid indices and treat them like
 
19233
         * non-existent optional parameters.
 
19234
         */
 
19235
 
 
19236
        h_str = duk_require_hstring(ctx, 0);
 
19237
        duk_require_valid_index(ctx, 1);
 
19238
 
 
19239
        if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
 
19240
                duk_set_top(ctx, 2);
 
19241
                duk_hex_decode(ctx, 1);
 
19242
                DUK_ASSERT_TOP(ctx, 2);
 
19243
        } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
 
19244
                duk_set_top(ctx, 2);
 
19245
                duk_base64_decode(ctx, 1);
 
19246
                DUK_ASSERT_TOP(ctx, 2);
 
19247
#ifdef DUK_USE_JSONX
 
19248
        } else if (h_str == DUK_HTHREAD_STRING_JSONX(thr)) {
 
19249
                duk_bi_json_parse_helper(ctx,
 
19250
                                         1 /*idx_value*/,
 
19251
                                         2 /*idx_replacer*/,
 
19252
                                         DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
 
19253
#endif
 
19254
#ifdef DUK_USE_JSONC
 
19255
        } else if (h_str == DUK_HTHREAD_STRING_JSONC(thr)) {
 
19256
                duk_bi_json_parse_helper(ctx,
 
19257
                                         1 /*idx_value*/,
 
19258
                                         2 /*idx_replacer*/,
 
19259
                                         DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
 
19260
#endif
 
19261
        } else {
 
19262
                return DUK_RET_TYPE_ERROR;
 
19263
        }
 
19264
        return 1;
 
19265
}
 
19266
 
 
19267
/*
 
19268
 *  Compact an object
 
19269
 */
 
19270
 
 
19271
duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
 
19272
        duk_compact(ctx, 0);
 
19273
        return 1;  /* return the argument object */
 
19274
}
 
19275
 
 
19276
#line 1 "duk_bi_error.c"
 
19277
/*
 
19278
 *  Error built-ins
 
19279
 */
 
19280
 
 
19281
/* include removed: duk_internal.h */
 
19282
 
 
19283
int duk_bi_error_constructor_shared(duk_context *ctx) {
 
19284
        /* Behavior for constructor and non-constructor call is
 
19285
         * the same except for augmenting the created error.  When
 
19286
         * called as a constructor, the caller (duk_new()) will handle
 
19287
         * augmentation; when called as normal function, we need to do
 
19288
         * it here.
 
19289
         */
 
19290
 
 
19291
        duk_hthread *thr = (duk_hthread *) ctx;
 
19292
        int bidx_prototype = duk_get_magic(ctx);
 
19293
 
 
19294
        /* same for both error and each subclass like TypeError */
 
19295
        int flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
 
19296
                              DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
 
19297
        
 
19298
        DUK_UNREF(thr);
 
19299
 
 
19300
        duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
 
19301
 
 
19302
        /* If message is undefined, the own property 'message' is not set at
 
19303
         * all to save property space.  An empty message is inherited anyway.
 
19304
         */
 
19305
        if (!duk_is_undefined(ctx, 0)) {
 
19306
                duk_to_string(ctx, 0);
 
19307
                duk_dup(ctx, 0);  /* [ message error message ] */
 
19308
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
 
19309
        }
 
19310
 
 
19311
        /* Augment the error if called as a normal function.  __FILE__ and __LINE__
 
19312
         * are not desirable in this case.
 
19313
         */
 
19314
 
 
19315
#ifdef DUK_USE_AUGMENT_ERROR_CREATE
 
19316
        if (!duk_is_constructor_call(ctx)) {
 
19317
                duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
 
19318
        }
 
19319
#endif
 
19320
 
 
19321
        return 1;
 
19322
}
 
19323
 
 
19324
int duk_bi_error_prototype_to_string(duk_context *ctx) {
 
19325
        /* FIXME: optimize with more direct internal access */
 
19326
 
 
19327
        duk_push_this(ctx);
 
19328
        if (!duk_is_object(ctx, -1)) {
 
19329
                goto type_error;
 
19330
        }
 
19331
 
 
19332
        /* [ ... this ] */
 
19333
 
 
19334
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
 
19335
        if (duk_is_undefined(ctx, -1)) {
 
19336
                duk_pop(ctx);
 
19337
                duk_push_string(ctx, "Error");
 
19338
        } else {
 
19339
                duk_to_string(ctx, -1);
 
19340
        }
 
19341
 
 
19342
        /* [ ... this name ] */
 
19343
 
 
19344
        /* FIXME: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
 
19345
         * accident or are they actually needed?  The first ToString()
 
19346
         * could conceivably return 'undefined'.
 
19347
         */
 
19348
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
 
19349
        if (duk_is_undefined(ctx, -1)) {
 
19350
                duk_pop(ctx);
 
19351
                duk_push_string(ctx, "");
 
19352
        } else {
 
19353
                duk_to_string(ctx, -1);
 
19354
        }
 
19355
 
 
19356
        /* [ ... this name message ] */
 
19357
 
 
19358
        if (duk_get_length(ctx, -2) == 0) {
 
19359
                /* name is empty -> return message */
 
19360
                return 1;
 
19361
        }
 
19362
        if (duk_get_length(ctx, -1) == 0) {
 
19363
                /* message is empty -> return name */
 
19364
                duk_pop(ctx);
 
19365
                return 1;
 
19366
        }
 
19367
        duk_push_string(ctx, ": ");
 
19368
        duk_insert(ctx, -2);  /* ... name ': ' message */
 
19369
        duk_concat(ctx, 3);
 
19370
 
 
19371
        return 1;
 
19372
 
 
19373
 type_error:
 
19374
        return DUK_RET_TYPE_ERROR;
 
19375
}
 
19376
 
 
19377
#ifdef DUK_USE_TRACEBACKS
 
19378
 
 
19379
/*
 
19380
 *  Traceback handling
 
19381
 *
 
19382
 *  The unified helper decodes the traceback and produces various requested
 
19383
 *  outputs.  It should be optimized for size, and may leave garbage on stack,
 
19384
 *  only the topmost return value matters.  For instance, traceback separator
 
19385
 *  and decoded strings are pushed even when looking for filename only.
 
19386
 *
 
19387
 *  NOTE: because user code can currently write to the tracedata array (or
 
19388
 *  replace it with something other than an array), the code below must
 
19389
 *  tolerate arbitrary tracedata.  It can throw errors etc, but cannot cause
 
19390
 *  a segfault or memory unsafe behavior.
 
19391
 */
 
19392
 
 
19393
/* constants arbitrary, chosen for small loads */
 
19394
#define DUK__OUTPUT_TYPE_TRACEBACK   (-1)
 
19395
#define DUK__OUTPUT_TYPE_FILENAME    0
 
19396
#define DUK__OUTPUT_TYPE_LINENUMBER  1
 
19397
 
 
19398
static int duk__traceback_getter_helper(duk_context *ctx, int output_type) {
 
19399
        duk_hthread *thr = (duk_hthread *) ctx;
 
19400
        int idx_td;
 
19401
        int i;
 
19402
        const char *str_tailcalled = " tailcalled";
 
19403
        const char *str_strict = " strict";
 
19404
        const char *str_construct = " construct";
 
19405
        const char *str_prevyield = " preventsyield";
 
19406
        const char *str_directeval = " directeval";
 
19407
        const char *str_empty = "";
 
19408
 
 
19409
        DUK_ASSERT_TOP(ctx, 0);  /* fixed arg count */
 
19410
 
 
19411
        duk_push_this(ctx);
 
19412
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TRACEDATA);
 
19413
        idx_td = duk_get_top_index(ctx);
 
19414
 
 
19415
        duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_TAB);
 
19416
        duk_push_this(ctx);
 
19417
        duk_to_string(ctx, -1);
 
19418
 
 
19419
        /* [ ... this tracedata sep ToString(this) ] */
 
19420
 
 
19421
        /* FIXME: skip null filename? */
 
19422
 
 
19423
        if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
 
19424
                int t;
 
19425
 
 
19426
                /* Current tracedata contains 2 entries per callstack entry. */
 
19427
                for (i = 0; ; i += 2) {
 
19428
                        int pc;
 
19429
                        int line;
 
19430
                        int flags;
 
19431
                        double d;
 
19432
                        const char *funcname;
 
19433
                        duk_hobject *h_func;
 
19434
                        duk_hstring *h_name;
 
19435
 
 
19436
                        duk_require_stack(ctx, 5);
 
19437
                        duk_get_prop_index(ctx, idx_td, i);
 
19438
                        duk_get_prop_index(ctx, idx_td, i + 1);
 
19439
                        d = duk_to_number(ctx, -1);
 
19440
                        pc = (int) DUK_FMOD(d, DUK_DOUBLE_2TO32);
 
19441
                        flags = (int) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
 
19442
                        t = duk_get_type(ctx, -2);
 
19443
 
 
19444
                        if (t == DUK_TYPE_OBJECT) {
 
19445
                                /*
 
19446
                                 *  Ecmascript/native function call
 
19447
                                 */
 
19448
 
 
19449
                                /* [ ... v1(func) v2(pc+flags) ] */
 
19450
 
 
19451
                                h_func = duk_get_hobject(ctx, -2);
 
19452
                                DUK_ASSERT(h_func != NULL);
 
19453
 
 
19454
                                duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
 
19455
                                duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
 
19456
 
 
19457
#if defined(DUK_USE_PC2LINE)
 
19458
                                duk_get_prop_stridx(ctx, -4, DUK_STRIDX_INT_PC2LINE);
 
19459
                                if (duk_is_buffer(ctx, -1)) {
 
19460
                                        duk_hbuffer_fixed *pc2line;
 
19461
                                        pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
 
19462
                                        DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line));
 
19463
                                        line = duk_hobject_pc2line_query(pc2line, (duk_uint_fast32_t) pc);
 
19464
                                } else {
 
19465
                                        line = 0;
 
19466
                                }
 
19467
                                duk_pop(ctx);
 
19468
#else
 
19469
                                line = 0;
 
19470
#endif
 
19471
 
 
19472
                                /* [ ... v1 v2 name filename ] */
 
19473
 
 
19474
                                if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
 
19475
                                        return 1;
 
19476
                                } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
 
19477
                                        duk_push_int(ctx, line);
 
19478
                                        return 1;
 
19479
                                }
 
19480
 
 
19481
                                h_name = duk_get_hstring(ctx, -2);  /* may be NULL */
 
19482
                                funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
 
19483
                                           "anon" : (const char *) DUK_HSTRING_GET_DATA(h_name);
 
19484
                                if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
 
19485
                                        duk_push_sprintf(ctx, "%s %s native%s%s%s%s%s",
 
19486
                                                         funcname,
 
19487
                                                         duk_get_string(ctx, -1),
 
19488
                                                         (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty,
 
19489
                                                         (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty,
 
19490
                                                         (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty,
 
19491
                                                         (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty,
 
19492
                                                         (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty);
 
19493
 
 
19494
                                } else {
 
19495
                                        duk_push_sprintf(ctx, "%s %s:%d%s%s%s%s%s",
 
19496
                                                         funcname,
 
19497
                                                         duk_get_string(ctx, -1),
 
19498
                                                         line,
 
19499
                                                         (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty,
 
19500
                                                         (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty,
 
19501
                                                         (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty,
 
19502
                                                         (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty,
 
19503
                                                         (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty);
 
19504
                                }
 
19505
                                duk_replace(ctx, -5);   /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
 
19506
                                duk_pop_n(ctx, 3);      /* -> [ ... str ] */
 
19507
                        } else if (t == DUK_TYPE_STRING) {
 
19508
                                /*
 
19509
                                 *  __FILE__ / __LINE__ entry, here 'pc' is line number directly.
 
19510
                                 *  Sometimes __FILE__ / __LINE__ is reported as the source for
 
19511
                                 *  the error (fileName, lineNumber), sometimes not.
 
19512
                                 */
 
19513
 
 
19514
                                /* [ ... v1(filename) v2(line+flags) ] */
 
19515
 
 
19516
                                if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
 
19517
                                        if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
 
19518
                                                duk_pop(ctx);
 
19519
                                                return 1;
 
19520
                                        } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
 
19521
                                                duk_push_int(ctx, pc);
 
19522
                                                return 1;
 
19523
                                        }
 
19524
                                }
 
19525
 
 
19526
                                duk_push_sprintf(ctx, "%s:%d",
 
19527
                                                 duk_get_string(ctx, -2), pc);
 
19528
                                duk_replace(ctx, -3);  /* [ ... v1 v2 str ] -> [ ... str v2 ] */
 
19529
                                duk_pop(ctx);          /* -> [ ... str ] */
 
19530
                        } else {
 
19531
                                /* unknown, ignore */
 
19532
                                duk_pop_2(ctx);
 
19533
                                break;
 
19534
                        }
 
19535
                }
 
19536
 
 
19537
                if (i >= DUK_USE_TRACEBACK_DEPTH * 2) {
 
19538
                        /* Possibly truncated; there is no explicit truncation
 
19539
                         * marker so this is the best we can do.
 
19540
                         */
 
19541
 
 
19542
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
 
19543
                }
 
19544
        }
 
19545
 
 
19546
        /* [ ... this tracedata sep ToString(this) str1 ... strN ] */
 
19547
 
 
19548
        if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
 
19549
                return 0;
 
19550
        } else {
 
19551
                duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
 
19552
                return 1;
 
19553
        }
 
19554
}
 
19555
 
 
19556
/* FIXME: output type could be encoded into native function 'magic' value to
 
19557
 * save space.
 
19558
 */
 
19559
 
 
19560
int duk_bi_error_prototype_stack_getter(duk_context *ctx) {
 
19561
        return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
 
19562
}
 
19563
 
 
19564
int duk_bi_error_prototype_filename_getter(duk_context *ctx) {
 
19565
        return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
 
19566
}
 
19567
 
 
19568
int duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
 
19569
        return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
 
19570
}
 
19571
 
 
19572
#undef DUK__OUTPUT_TYPE_TRACEBACK
 
19573
#undef DUK__OUTPUT_TYPE_FILENAME
 
19574
#undef DUK__OUTPUT_TYPE_LINENUMBER
 
19575
 
 
19576
#else  /* DUK_USE_TRACEBACKS */
 
19577
 
 
19578
/*
 
19579
 *  Traceback handling when tracebacks disabled.
 
19580
 *
 
19581
 *  The fileName / lineNumber stubs are now necessary because built-in
 
19582
 *  data will include the accessor properties in Error.prototype.  If those
 
19583
 *  are removed for builds without tracebacks, these can also be removed.
 
19584
 *  'stack' should still be present and produce a ToString() equivalent:
 
19585
 *  this is useful for user code which prints a stacktrace and expects to
 
19586
 *  see something useful.  A normal stacktrace also begins with a ToString()
 
19587
 *  of the error so this makes sense.
 
19588
 */
 
19589
 
 
19590
int duk_bi_error_prototype_stack_getter(duk_context *ctx) {
 
19591
        /* FIXME: remove this native function and map 'stack' accessor
 
19592
         * to the toString() implementation directly.
 
19593
         */
 
19594
        return duk_bi_error_prototype_to_string(ctx);
 
19595
}
 
19596
 
 
19597
int duk_bi_error_prototype_filename_getter(duk_context *ctx) {
 
19598
        DUK_UNREF(ctx);
 
19599
        return 0;
 
19600
}
 
19601
 
 
19602
int duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
 
19603
        DUK_UNREF(ctx);
 
19604
        return 0;
 
19605
}
 
19606
 
 
19607
#endif  /* DUK_USE_TRACEBACKS */
 
19608
 
 
19609
int duk_bi_error_prototype_nop_setter(duk_context *ctx) {
 
19610
        /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op.
 
19611
         * User can use Object.defineProperty() to override this behavior.
 
19612
         */
 
19613
        DUK_ASSERT_TOP(ctx, 1);  /* fixed arg count */
 
19614
        DUK_UNREF(ctx);
 
19615
        return 0;
 
19616
}
 
19617
#line 1 "duk_bi_function.c"
 
19618
/*
 
19619
 *  Function built-ins
 
19620
 */
 
19621
 
 
19622
/* include removed: duk_internal.h */
 
19623
 
 
19624
int duk_bi_function_constructor(duk_context *ctx) {
 
19625
        duk_hthread *thr = (duk_hthread *) ctx;
 
19626
        int num_args;
 
19627
        int i;
 
19628
        int comp_flags;
 
19629
        duk_hcompiledfunction *func;
 
19630
        duk_hobject *outer_lex_env;
 
19631
        duk_hobject *outer_var_env;
 
19632
 
 
19633
        /* normal and constructor calls have identical semantics */
 
19634
 
 
19635
        num_args = duk_get_top(ctx);
 
19636
 
 
19637
        for (i = 0; i < num_args; i++) {
 
19638
                duk_to_string(ctx, i);
 
19639
        }
 
19640
 
 
19641
        if (num_args == 0) {
 
19642
                duk_push_string(ctx, "");
 
19643
                duk_push_string(ctx, "");
 
19644
        } else if (num_args == 1) {
 
19645
                duk_push_string(ctx, "");
 
19646
        } else {
 
19647
                duk_insert(ctx, 0);   /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
 
19648
                duk_push_string(ctx, ",");
 
19649
                duk_insert(ctx, 1);
 
19650
                duk_join(ctx, num_args - 1);
 
19651
        }
 
19652
 
 
19653
        /* [ body formals ], formals is comma separated list that needs to be parsed */
 
19654
 
 
19655
        DUK_ASSERT_TOP(ctx, 2);
 
19656
 
 
19657
        /* FIXME: this placeholder is not always correct, but use for now.
 
19658
         * It will fail in corner cases; see test-dev-func-cons-args.js.
 
19659
         */
 
19660
        duk_push_string(ctx, "function(");
 
19661
        duk_dup(ctx, 1);
 
19662
        duk_push_string(ctx, "){");
 
19663
        duk_dup(ctx, 0);
 
19664
        duk_push_string(ctx, "}");
 
19665
        duk_concat(ctx, 5);
 
19666
 
 
19667
        DUK_ASSERT_TOP(ctx, 3);
 
19668
 
 
19669
        /* FIXME: uses internal API */
 
19670
 
 
19671
        /* strictness is not inherited, intentional */
 
19672
        comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
 
19673
 
 
19674
        duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE);  /* XXX: copy from caller? */
 
19675
        duk_js_compile(thr, comp_flags);
 
19676
        func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
 
19677
        DUK_ASSERT(func != NULL);
 
19678
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
 
19679
 
 
19680
        /* only outer_lex_env matters, as functions always get a new
 
19681
         * variable declaration environment.
 
19682
         */
 
19683
 
 
19684
        outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
19685
        outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
19686
 
 
19687
        duk_js_push_closure(thr, func, outer_var_env, outer_lex_env);
 
19688
 
 
19689
        return 1;
 
19690
}
 
19691
 
 
19692
int duk_bi_function_prototype(duk_context *ctx) {
 
19693
        /* ignore arguments, return undefined (E5 Section 15.3.4) */
 
19694
        DUK_UNREF(ctx);
 
19695
        return 0;
 
19696
}
 
19697
 
 
19698
int duk_bi_function_prototype_to_string(duk_context *ctx) {
 
19699
        duk_tval *tv;
 
19700
 
 
19701
        /*
 
19702
         *  E5 Section 15.3.4.2 places few requirements on the output of
 
19703
         *  this function:
 
19704
         *
 
19705
         *    - The result is an implementation dependent representation
 
19706
         *      of the function; in particular
 
19707
         *
 
19708
         *    - The result must follow the syntax of a FunctionDeclaration.
 
19709
         *      In particular, the function must have a name (even in the
 
19710
         *      case of an anonymous function or a function with an empty
 
19711
         *      name).
 
19712
         *
 
19713
         *    - Note in particular that the output does NOT need to compile
 
19714
         *      into anything useful.
 
19715
         */
 
19716
 
 
19717
 
 
19718
        /* FIXME: faster internal way to get this */
 
19719
        duk_push_this(ctx);
 
19720
        tv = duk_get_tval(ctx, -1);
 
19721
        DUK_ASSERT(tv != NULL);
 
19722
 
 
19723
        if (DUK_TVAL_IS_OBJECT(tv)) {
 
19724
                duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
 
19725
                const char *func_name = "anonymous";
 
19726
 
 
19727
                /* FIXME: rework, it would be nice to avoid C formatting functions to
 
19728
                 * ensure there are no Unicode issues.
 
19729
                 */
 
19730
 
 
19731
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
 
19732
                if (!duk_is_undefined(ctx, -1)) {
 
19733
                        func_name = duk_to_string(ctx, -1);
 
19734
                        DUK_ASSERT(func_name != NULL);
 
19735
 
 
19736
                        if (func_name[0] == (char) 0) {
 
19737
                                func_name = "empty";
 
19738
                        }
 
19739
                }
 
19740
 
 
19741
                if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
 
19742
                        /* FIXME: actual source, if available */
 
19743
                        duk_push_sprintf(ctx, "function %s() {/* source code */}", func_name);
 
19744
                } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
 
19745
                        duk_push_sprintf(ctx, "function %s() {/* native code */}", func_name);
 
19746
                } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
 
19747
                        duk_push_sprintf(ctx, "function %s() {/* bound */}", func_name);
 
19748
                } else {
 
19749
                        goto type_error;
 
19750
                }
 
19751
        } else {
 
19752
                goto type_error;
 
19753
        }
 
19754
 
 
19755
        return 1;
 
19756
 
 
19757
 type_error:
 
19758
        return DUK_RET_TYPE_ERROR;
 
19759
}
 
19760
 
 
19761
int duk_bi_function_prototype_apply(duk_context *ctx) {
 
19762
        unsigned int len;
 
19763
        unsigned int i;
 
19764
 
 
19765
        /* FIXME: stack checks */
 
19766
 
 
19767
        DUK_ASSERT_TOP(ctx, 2);  /* not a vararg function */
 
19768
 
 
19769
        duk_push_this(ctx);
 
19770
        if (!duk_is_callable(ctx, -1)) {
 
19771
                DUK_DDDPRINT("func is not callable");
 
19772
                goto type_error;
 
19773
        }
 
19774
        duk_insert(ctx, 0);
 
19775
        DUK_ASSERT_TOP(ctx, 3);
 
19776
 
 
19777
        DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
 
19778
                     duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), duk_get_tval(ctx, 2));
 
19779
 
 
19780
        /* [ func thisArg argArray ] */
 
19781
 
 
19782
        if (duk_is_null_or_undefined(ctx, 2)) {
 
19783
                DUK_DDDPRINT("argArray is null/undefined, no args");
 
19784
                len = 0;
 
19785
        } else if (!duk_is_object(ctx, 2)) {
 
19786
                goto type_error;
 
19787
        } else {
 
19788
                DUK_DDDPRINT("argArray is an object");
 
19789
 
 
19790
                /* FIXME: make this an internal helper */
 
19791
                duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
 
19792
                len = duk_to_uint32(ctx, -1);
 
19793
                duk_pop(ctx);
 
19794
 
 
19795
                duk_require_stack(ctx, len);  /* FIXME: more? */
 
19796
 
 
19797
                DUK_DDDPRINT("argArray length is %d", len);
 
19798
                for (i = 0; i < len; i++) {
 
19799
                        duk_get_prop_index(ctx, 2, i);
 
19800
                }
 
19801
        }
 
19802
        duk_remove(ctx, 2);
 
19803
        DUK_ASSERT_TOP(ctx, 2 + len);
 
19804
 
 
19805
        /* [ func thisArg arg1 ... argN ] */
 
19806
        
 
19807
        DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%d",
 
19808
                     duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), len);
 
19809
        duk_call_method(ctx, len);
 
19810
        return 1;
 
19811
 
 
19812
 type_error:
 
19813
        return DUK_RET_TYPE_ERROR;
 
19814
}
 
19815
 
 
19816
int duk_bi_function_prototype_call(duk_context *ctx) {
 
19817
        int nargs;
 
19818
 
 
19819
        /* Step 1 is not necessary because duk_call_method() will take
 
19820
         * care of it.
 
19821
         */
 
19822
 
 
19823
        /* vararg function, thisArg needs special handling */
 
19824
        nargs = duk_get_top(ctx);  /* = 1 + arg count */
 
19825
        if (nargs == 0) {
 
19826
                duk_push_undefined(ctx);
 
19827
                nargs++;
 
19828
        }
 
19829
        DUK_ASSERT(nargs >= 1);
 
19830
 
 
19831
        /* [ thisArg arg1 ... argN ] */
 
19832
 
 
19833
        duk_push_this(ctx);  /* 'func' in the algorithm */
 
19834
        duk_insert(ctx, 0);
 
19835
 
 
19836
        /* [ func thisArg arg1 ... argN ] */
 
19837
 
 
19838
        DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%d, top=%d",
 
19839
                     duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), nargs - 1, duk_get_top(ctx));
 
19840
        duk_call_method(ctx, nargs - 1);        
 
19841
        return 1;
 
19842
}
 
19843
 
 
19844
/* FIXME: the implementation now assumes "chained" bound functions,
 
19845
 * whereas "collapsed" bound functions (where there is ever only
 
19846
 * one bound function which directly points to a non-bound, final
 
19847
 * function) would require a "collapsing" implementation which
 
19848
 * merges argument lists etc here.
 
19849
 */
 
19850
int duk_bi_function_prototype_bind(duk_context *ctx) {
 
19851
        duk_hobject *h_target;
 
19852
        int nargs;
 
19853
        int i;
 
19854
 
 
19855
        /* FIXME: stack checks */
 
19856
 
 
19857
        /* vararg function, careful arg handling (e.g. thisArg may not be present) */
 
19858
        nargs = duk_get_top(ctx);  /* = 1 + arg count */
 
19859
        if (nargs == 0) {
 
19860
                duk_push_undefined(ctx);
 
19861
                nargs++;
 
19862
        }
 
19863
        DUK_ASSERT(nargs >= 1);
 
19864
 
 
19865
        duk_push_this(ctx);
 
19866
        if (!duk_is_callable(ctx, -1)) {
 
19867
                DUK_DDDPRINT("func is not callable");
 
19868
                goto type_error;
 
19869
        }
 
19870
 
 
19871
        /* [ thisArg arg1 ... argN func ]  (thisArg+args == nargs total) */
 
19872
        DUK_ASSERT_TOP(ctx, nargs + 1);
 
19873
 
 
19874
        /* create bound function object */
 
19875
        duk_push_object_helper(ctx,
 
19876
                               DUK_HOBJECT_FLAG_EXTENSIBLE |
 
19877
                               DUK_HOBJECT_FLAG_BOUND |
 
19878
                               DUK_HOBJECT_FLAG_CONSTRUCTABLE |
 
19879
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
 
19880
                               DUK_BIDX_FUNCTION_PROTOTYPE);
 
19881
 
 
19882
        /* FIXME: check hobject flags (e.g. strict) */
 
19883
 
 
19884
        /* [ thisArg arg1 ... argN func boundFunc ] */
 
19885
        duk_dup(ctx, -2);  /* func */
 
19886
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
 
19887
 
 
19888
        duk_dup(ctx, 0);   /* thisArg */
 
19889
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
 
19890
 
 
19891
        duk_push_array(ctx);
 
19892
 
 
19893
        /* [ thisArg arg1 ... argN func boundFunc argArray ] */
 
19894
 
 
19895
        for (i = 0; i < nargs - 1; i++) {
 
19896
                duk_dup(ctx, 1 + i);
 
19897
                duk_put_prop_index(ctx, -2, i);
 
19898
        }
 
19899
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
 
19900
 
 
19901
        /* [ thisArg arg1 ... argN func boundFunc ] */
 
19902
 
 
19903
        /* bound function 'length' property is interesting */
 
19904
        h_target = duk_get_hobject(ctx, -2);
 
19905
        DUK_ASSERT(h_target != NULL);
 
19906
        if (DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
 
19907
                int tmp;
 
19908
                duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
 
19909
                tmp = duk_to_int(ctx, -1) - (nargs - 1);  /* step 15.a */
 
19910
                duk_pop(ctx);
 
19911
                duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
 
19912
        } else {
 
19913
                duk_push_int(ctx, 0);
 
19914
        }
 
19915
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);  /* attrs in E5 Section 15.3.5.1 */
 
19916
 
 
19917
        /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
 
19918
        duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
 
19919
        duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
 
19920
 
 
19921
        /* these non-standard properties are copied for convenience */
 
19922
        /* FIXME: 'copy properties' API call? */
 
19923
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
 
19924
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
 
19925
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
 
19926
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
 
19927
 
 
19928
        DUK_DDDPRINT("created bound function: %!iT", duk_get_tval(ctx, -1));
 
19929
 
 
19930
        return 1;
 
19931
 
 
19932
 type_error:
 
19933
        return DUK_RET_TYPE_ERROR;
 
19934
}
 
19935
 
 
19936
#line 1 "duk_bi_global.c"
 
19937
/*
 
19938
 *  Global object built-ins
 
19939
 */
 
19940
 
 
19941
/* include removed: duk_internal.h */
 
19942
 
 
19943
/*
 
19944
 *  Encoding/decoding helpers
 
19945
 */
 
19946
 
 
19947
/* Macros for creating and checking bitmasks for character encoding.
 
19948
 * Bit number is a bit counterintuitive, but minimizes code size.
 
19949
 */
 
19950
#define DUK__MKBITS(a,b,c,d,e,f,g,h)  ((unsigned char) ( \
 
19951
        ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
 
19952
        ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
 
19953
        ))
 
19954
#define DUK__CHECK_BITMASK(table,cp)  ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
 
19955
 
 
19956
/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
 
19957
static unsigned char duk__encode_uriunescaped_table[16] = {
 
19958
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
 
19959
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
 
19960
        DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x20-0x2f */
 
19961
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1),  /* 0x30-0x3f */
 
19962
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
 
19963
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
 
19964
        DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
 
19965
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0),  /* 0x70-0x7f */
 
19966
};
 
19967
 
 
19968
/* E5.1 Section 15.1.3.4: uriUnescaped */
 
19969
static unsigned char duk__encode_uricomponent_unescaped_table[16] = {
 
19970
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
 
19971
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
 
19972
        DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0),  /* 0x20-0x2f */
 
19973
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
 
19974
        DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
 
19975
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
 
19976
        DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
 
19977
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0),  /* 0x70-0x7f */
 
19978
};
 
19979
 
 
19980
/* E5.1 Section 15.1.3.1: uriReserved + '#' */
 
19981
static unsigned char duk__decode_uri_reserved_table[16] = {
 
19982
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
 
19983
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
 
19984
        DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1),  /* 0x20-0x2f */
 
19985
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1),  /* 0x30-0x3f */
 
19986
        DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x40-0x4f */
 
19987
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x50-0x5f */
 
19988
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x60-0x6f */
 
19989
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x70-0x7f */
 
19990
};
 
19991
 
 
19992
/* E5.1 Section 15.1.3.2: empty */
 
19993
static unsigned char duk__decode_uri_component_reserved_table[16] = {
 
19994
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
 
19995
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
 
19996
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x20-0x2f */
 
19997
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
 
19998
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x40-0x4f */
 
19999
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x50-0x5f */
 
20000
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x60-0x6f */
 
20001
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x70-0x7f */
 
20002
};
 
20003
 
 
20004
#ifdef DUK_USE_SECTION_B
 
20005
/* E5.1 Section B.2.2, step 7. */
 
20006
static unsigned char duk__escape_unescaped_table[16] = {
 
20007
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
 
20008
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
 
20009
        DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1),  /* 0x20-0x2f */
 
20010
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
 
20011
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
 
20012
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
 
20013
        DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
 
20014
        DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0)   /* 0x70-0x7f */
 
20015
};
 
20016
#endif  /* DUK_USE_SECTION_B */
 
20017
 
 
20018
typedef struct {
 
20019
        duk_hthread *thr;
 
20020
        duk_hstring *h_str;
 
20021
        duk_hbuffer_dynamic *h_buf;
 
20022
        duk_uint8_t *p;
 
20023
        duk_uint8_t *p_start;
 
20024
        duk_uint8_t *p_end;
 
20025
} duk__transform_context;
 
20026
 
 
20027
typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp);
 
20028
 
 
20029
/* FIXME: refactor and share with other code */
 
20030
static duk_small_int_t duk__decode_hex_escape(duk_uint8_t *p, duk_small_int_t n) {
 
20031
        duk_small_int_t ch;
 
20032
        duk_small_int_t t = 0;
 
20033
 
 
20034
        while (n > 0) {
 
20035
                t = t * 16;
 
20036
                ch = (int) (*p++);
 
20037
                if (ch >= (int) '0' && ch <= (int) '9') {
 
20038
                        t += ch - ((int) '0');
 
20039
                } else if (ch >= (int) 'a' && ch <= (int) 'f') {
 
20040
                        t += ch - ((int) 'a') + 0x0a;
 
20041
                } else if (ch >= (int) 'A' && ch <= (int) 'F') {
 
20042
                        t += ch - ((int) 'A') + 0x0a;
 
20043
                } else {
 
20044
                        return -1;
 
20045
                }
 
20046
                n--;
 
20047
        }
 
20048
        return t;
 
20049
}
 
20050
 
 
20051
static int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, void *udata) {
 
20052
        duk_hthread *thr = (duk_hthread *) ctx;
 
20053
        duk__transform_context tfm_ctx_alloc;
 
20054
        duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
 
20055
        duk_codepoint_t cp;
 
20056
 
 
20057
        tfm_ctx->thr = thr;
 
20058
 
 
20059
        tfm_ctx->h_str = duk_to_hstring(ctx, 0);
 
20060
        DUK_ASSERT(tfm_ctx->h_str != NULL);
 
20061
 
 
20062
        (void) duk_push_dynamic_buffer(ctx, 0);
 
20063
        tfm_ctx->h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
20064
        DUK_ASSERT(tfm_ctx->h_buf != NULL);
 
20065
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(tfm_ctx->h_buf));
 
20066
 
 
20067
        tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
 
20068
        tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
 
20069
        tfm_ctx->p = tfm_ctx->p_start;
 
20070
 
 
20071
        while (tfm_ctx->p < tfm_ctx->p_end) {
 
20072
                cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
 
20073
                callback(tfm_ctx, udata, cp);
 
20074
        }
 
20075
 
 
20076
        duk_to_string(ctx, -1);
 
20077
        return 1;
 
20078
}
 
20079
 
 
20080
static void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
 
20081
        duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
 
20082
        duk_uint8_t buf[3];
 
20083
        duk_small_int_t len;
 
20084
        duk_codepoint_t cp1, cp2;
 
20085
        duk_small_int_t i, t;
 
20086
        duk_uint8_t *unescaped_table = (duk_uint8_t *) udata;
 
20087
 
 
20088
        if (cp < 0) {
 
20089
                goto uri_error;
 
20090
        } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
 
20091
                duk_hbuffer_append_byte(tfm_ctx->thr, tfm_ctx->h_buf, (duk_uint8_t) cp);
 
20092
                return;
 
20093
        } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
 
20094
                goto uri_error;
 
20095
        } else if (cp >= 0xd800L && cp <= 0xdbffL) {
 
20096
                /* Needs lookahead */
 
20097
                if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
 
20098
                        goto uri_error;
 
20099
                }
 
20100
                if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
 
20101
                        goto uri_error;
 
20102
                }
 
20103
                cp1 = cp;
 
20104
                cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
 
20105
        } else if (cp > 0x10ffffL) {
 
20106
                /* Although we can allow non-BMP characters (they'll decode
 
20107
                 * back into surrogate pairs), we don't allow extended UTF-8
 
20108
                 * characters; they would encode to URIs which won't decode
 
20109
                 * back because of strict UTF-8 checks in URI decoding.
 
20110
                 * (However, we could just as well allow them here.)
 
20111
                 */
 
20112
                goto uri_error;
 
20113
        } else {
 
20114
                /* Non-BMP characters within valid UTF-8 range: encode as is.
 
20115
                 * They'll decode back into surrogate pairs.
 
20116
                 */
 
20117
                ;
 
20118
        }
 
20119
 
 
20120
        len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
 
20121
        buf[0] = (duk_uint8_t) '%';
 
20122
        for (i = 0; i < len; i++) {
 
20123
                t = (int) xutf8_buf[i];
 
20124
                buf[1] = (duk_uint8_t) duk_uc_nybbles[t >> 4];
 
20125
                buf[2] = (duk_uint8_t) duk_uc_nybbles[t & 0x0f];
 
20126
                duk_hbuffer_append_bytes(tfm_ctx->thr, tfm_ctx->h_buf, buf, 3);
 
20127
        }
 
20128
        return;
 
20129
 
 
20130
 uri_error:
 
20131
        DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
 
20132
}
 
20133
 
 
20134
static void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
 
20135
        duk_uint8_t *reserved_table = (duk_uint8_t *) udata;
 
20136
        duk_small_uint_t utf8_blen;
 
20137
        duk_codepoint_t min_cp;
 
20138
        duk_small_int_t t;  /* must be signed */
 
20139
        duk_small_uint_t i;
 
20140
 
 
20141
        if (cp == (duk_codepoint_t) '%') {
 
20142
                duk_uint8_t *p = tfm_ctx->p;
 
20143
                duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p);  /* bytes left */
 
20144
 
 
20145
                DUK_DDDPRINT("percent encoding, left=%d", (int) left);
 
20146
 
 
20147
                if (left < 2) {
 
20148
                        goto uri_error;
 
20149
                }
 
20150
 
 
20151
                t = duk__decode_hex_escape(p, 2);
 
20152
                DUK_DDDPRINT("first byte: %d", t);
 
20153
                if (t < 0) {
 
20154
                        goto uri_error;
 
20155
                }
 
20156
 
 
20157
                if (t < 128) {
 
20158
                        if (DUK__CHECK_BITMASK(reserved_table, t)) {
 
20159
                                /* decode '%xx' to '%xx' if decoded char in reserved set */
 
20160
                                DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
 
20161
                                duk_hbuffer_append_bytes(tfm_ctx->thr, tfm_ctx->h_buf, (duk_uint8_t *) (p - 1), 3);
 
20162
                        } else {
 
20163
                                duk_hbuffer_append_byte(tfm_ctx->thr, tfm_ctx->h_buf, (duk_uint8_t) t);
 
20164
                        }
 
20165
                        tfm_ctx->p += 2;
 
20166
                        return;
 
20167
                }
 
20168
 
 
20169
                /* Decode UTF-8 codepoint from a sequence of hex escapes.  The
 
20170
                 * first byte of the sequence has been decoded to 't'.
 
20171
                 *
 
20172
                 * Note that UTF-8 validation must be strict according to the
 
20173
                 * specification: E5.1 Section 15.1.3, decode algorithm step
 
20174
                 * 4.d.vii.8.  URIError from non-shortest encodings is also
 
20175
                 * specifically noted in the spec.
 
20176
                 */
 
20177
 
 
20178
                DUK_ASSERT(t >= 0x80);
 
20179
                if (t < 0xc0) {
 
20180
                        /* continuation byte */
 
20181
                        goto uri_error;
 
20182
                } else if (t < 0xe0) {
 
20183
                        /* 110x xxxx; 2 bytes */
 
20184
                        utf8_blen = 2;
 
20185
                        min_cp = 0x80L;
 
20186
                        cp = t & 0x1f;
 
20187
                } else if (t < 0xf0) {
 
20188
                        /* 1110 xxxx; 3 bytes */
 
20189
                        utf8_blen = 3;
 
20190
                        min_cp = 0x800L;
 
20191
                        cp = t & 0x0f;
 
20192
                } else if (t < 0xf8) {
 
20193
                        /* 1111 0xxx; 4 bytes */
 
20194
                        utf8_blen = 4;
 
20195
                        min_cp = 0x10000L;
 
20196
                        cp = t & 0x07;
 
20197
                } else {
 
20198
                        /* extended utf-8 not allowed for URIs */
 
20199
                        goto uri_error;
 
20200
                }
 
20201
 
 
20202
                if (left < utf8_blen * 3 - 1) {
 
20203
                        /* '%xx%xx...%xx', p points to char after first '%' */
 
20204
                        goto uri_error;
 
20205
                }
 
20206
 
 
20207
                p += 3;
 
20208
                for (i = 1; i < utf8_blen; i++) {
 
20209
                        /* p points to digit part ('%xy', p points to 'x') */
 
20210
                        t = duk__decode_hex_escape(p, 2);
 
20211
                        DUK_DDDPRINT("i=%d utf8_blen=%d cp=%d t=0x%02x", i, utf8_blen, cp,t);
 
20212
                        if (t < 0) {
 
20213
                                goto uri_error;
 
20214
                        }
 
20215
                        if ((t & 0xc0) != 0x80) {
 
20216
                                goto uri_error;
 
20217
                        }
 
20218
                        cp = (cp << 6) + (t & 0x3f);
 
20219
                        p += 3;
 
20220
                }
 
20221
                p--;  /* p overshoots */
 
20222
                tfm_ctx->p = p;
 
20223
 
 
20224
                DUK_DDDPRINT("final cp=%d, min_cp=%d", cp, min_cp);
 
20225
 
 
20226
                if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
 
20227
                        goto uri_error;
 
20228
                }
 
20229
 
 
20230
                /* The E5.1 algorithm checks whether or not a decoded codepoint
 
20231
                 * is below 0x80 and perhaps may be in the "reserved" set.
 
20232
                 * This seems pointless because the single byte UTF-8 case is
 
20233
                 * handled separately, and non-shortest encodings are rejected.
 
20234
                 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
 
20235
                 * the reserved set.
 
20236
                 */
 
20237
 
 
20238
                /* utf-8 validation ensures these */
 
20239
                DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
 
20240
 
 
20241
                if (cp >= 0x10000L) {
 
20242
                        cp -= 0x10000L;
 
20243
                        DUK_ASSERT(cp < 0x100000L);
 
20244
                        duk_hbuffer_append_xutf8(tfm_ctx->thr, tfm_ctx->h_buf, (duk_ucodepoint_t) ((cp >> 10) + 0xd800L));
 
20245
                        duk_hbuffer_append_xutf8(tfm_ctx->thr, tfm_ctx->h_buf, (duk_ucodepoint_t) ((cp & 0x03ffUL) + 0xdc00L));
 
20246
                } else {
 
20247
                        duk_hbuffer_append_xutf8(tfm_ctx->thr, tfm_ctx->h_buf, (duk_ucodepoint_t) cp);
 
20248
                }
 
20249
        } else {
 
20250
                duk_hbuffer_append_xutf8(tfm_ctx->thr, tfm_ctx->h_buf, (duk_ucodepoint_t) cp);
 
20251
        }
 
20252
        return;
 
20253
 
 
20254
 uri_error:
 
20255
        DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
 
20256
}
 
20257
 
 
20258
#ifdef DUK_USE_SECTION_B
 
20259
static void duk__transform_callback_escape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
 
20260
        duk_uint8_t buf[6];
 
20261
        duk_small_int_t len;
 
20262
 
 
20263
        DUK_UNREF(udata);
 
20264
 
 
20265
        if (cp < 0) {
 
20266
                goto esc_error;
 
20267
        } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
 
20268
                buf[0] = (duk_uint8_t) cp;
 
20269
                len = 1;
 
20270
        } else if (cp < 0x100L) {
 
20271
                buf[0] = (duk_uint8_t) '%';
 
20272
                buf[1] = (duk_uint8_t) duk_uc_nybbles[cp >> 4];
 
20273
                buf[2] = (duk_uint8_t) duk_uc_nybbles[cp & 0x0f];
 
20274
                len = 3;
 
20275
        } else if (cp < 0x10000L) {
 
20276
                buf[0] = (duk_uint8_t) '%';
 
20277
                buf[1] = (duk_uint8_t) 'u';
 
20278
                buf[2] = (duk_uint8_t) duk_uc_nybbles[cp >> 12];
 
20279
                buf[3] = (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f];
 
20280
                buf[4] = (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f];
 
20281
                buf[5] = (duk_uint8_t) duk_uc_nybbles[cp & 0x0f];
 
20282
                len = 6;
 
20283
        } else {
 
20284
                /* Characters outside BMP cannot be escape()'d.  We could
 
20285
                 * encode them as surrogate pairs (for codepoints inside
 
20286
                 * valid UTF-8 range, but not extended UTF-8).  Because
 
20287
                 * escape() and unescape() are legacy functions, we don't.
 
20288
                 */
 
20289
                goto esc_error;
 
20290
        }
 
20291
 
 
20292
        duk_hbuffer_append_bytes(tfm_ctx->thr, tfm_ctx->h_buf, buf, len);
 
20293
        return;
 
20294
 
 
20295
 esc_error:
 
20296
        DUK_ERROR(tfm_ctx->thr, DUK_ERR_TYPE_ERROR, "invalid input");
 
20297
}
 
20298
 
 
20299
static void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, void *udata, duk_codepoint_t cp) {
 
20300
        duk_small_int_t t;
 
20301
 
 
20302
        DUK_UNREF(udata);
 
20303
 
 
20304
        if (cp == (duk_codepoint_t) '%') {
 
20305
                duk_uint8_t *p = tfm_ctx->p;
 
20306
                duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p);  /* bytes left */
 
20307
 
 
20308
                if (left >= 5 && p[0] == 'u' &&
 
20309
                    ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
 
20310
                        cp = (duk_codepoint_t) t;
 
20311
                        tfm_ctx->p += 5;
 
20312
                } else if (left >= 2 &&
 
20313
                           ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
 
20314
                        cp = (duk_codepoint_t) t;
 
20315
                        tfm_ctx->p += 2;
 
20316
                }
 
20317
        }
 
20318
 
 
20319
        duk_hbuffer_append_xutf8(tfm_ctx->thr, tfm_ctx->h_buf, cp);
 
20320
}
 
20321
#endif  /* DUK_USE_SECTION_B */
 
20322
 
 
20323
/*
 
20324
 *  Eval
 
20325
 *
 
20326
 *  Eval needs to handle both a "direct eval" and an "indirect eval".
 
20327
 *  Direct eval handling needs access to the caller's activation so that its
 
20328
 *  lexical environment can be accessed.  A direct eval is only possible from
 
20329
 *  Ecmascript code; an indirect eval call is possible also from C code.
 
20330
 *  When an indirect eval call is made from C code, there may not be a
 
20331
 *  calling activation at all which needs careful handling.
 
20332
 */
 
20333
 
 
20334
int duk_bi_global_object_eval(duk_context *ctx) {
 
20335
        duk_hthread *thr = (duk_hthread *) ctx;
 
20336
        duk_hstring *h;
 
20337
        duk_activation *act_caller;
 
20338
        duk_activation *act_eval;
 
20339
        duk_activation *act;
 
20340
        duk_hcompiledfunction *func;
 
20341
        duk_hobject *outer_lex_env;
 
20342
        duk_hobject *outer_var_env;
 
20343
        int this_to_global = 1;
 
20344
        int comp_flags;
 
20345
 
 
20346
        DUK_ASSERT_TOP(ctx, 1);
 
20347
        DUK_ASSERT(thr->callstack_top >= 1);  /* at least this function exists */
 
20348
        DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
 
20349
                   (thr->callstack_top >= 2));  /* if direct eval, calling activation must exist */
 
20350
 
 
20351
        /*
 
20352
         *  callstack_top - 1 --> this function
 
20353
         *  callstack_top - 2 --> caller (may not exist)
 
20354
         *
 
20355
         *  If called directly from C, callstack_top might be 1.  If calling
 
20356
         *  activation doesn't exist, call must be indirect.
 
20357
         */
 
20358
 
 
20359
        h = duk_get_hstring(ctx, 0);
 
20360
        if (!h) {
 
20361
                return 1;  /* return arg as-is */
 
20362
        }
 
20363
 
 
20364
        comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
 
20365
        act_eval = thr->callstack + thr->callstack_top - 1;    /* this function */
 
20366
        if (thr->callstack_top >= 2) {
 
20367
                /* Have a calling activation, check for direct eval (otherwise
 
20368
                 * assume indirect eval.
 
20369
                 */
 
20370
                act_caller = thr->callstack + thr->callstack_top - 2;  /* caller */
 
20371
                if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
 
20372
                    (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
 
20373
                        /* Only direct eval inherits strictness from calling code
 
20374
                         * (E5.1 Section 10.1.1).
 
20375
                         */
 
20376
                        comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
 
20377
                }
 
20378
        } else {
 
20379
                DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
 
20380
        }
 
20381
        act_caller = NULL;  /* avoid dereference after potential callstack realloc */
 
20382
        act_eval = NULL;
 
20383
 
 
20384
        duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT);  /* XXX: copy from caller? */
 
20385
        duk_js_compile(thr, comp_flags);
 
20386
        func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
 
20387
        DUK_ASSERT(func != NULL);
 
20388
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
 
20389
 
 
20390
        /* E5 Section 10.4.2 */
 
20391
        DUK_ASSERT(thr->callstack_top >= 1);
 
20392
        act = thr->callstack + thr->callstack_top - 1;  /* this function */
 
20393
        if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {    
 
20394
                DUK_ASSERT(thr->callstack_top >= 2);
 
20395
                act = thr->callstack + thr->callstack_top - 2;  /* caller */
 
20396
                if (act->lex_env == NULL) {
 
20397
                        DUK_ASSERT(act->var_env == NULL);
 
20398
                        DUK_DDDPRINT("delayed environment initialization");
 
20399
 
 
20400
                        /* this may have side effects, so re-lookup act */
 
20401
                        duk_js_init_activation_environment_records_delayed(thr, act);
 
20402
                        act = thr->callstack + thr->callstack_top - 2;
 
20403
                }
 
20404
                DUK_ASSERT(act->lex_env != NULL);
 
20405
                DUK_ASSERT(act->var_env != NULL);
 
20406
 
 
20407
                this_to_global = 0;
 
20408
 
 
20409
                if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
 
20410
                        duk_hobject *new_env;
 
20411
                        duk_hobject *act_lex_env;
 
20412
 
 
20413
                        DUK_DDDPRINT("direct eval call to a strict function -> "
 
20414
                                     "var_env and lex_env to a fresh env, "
 
20415
                                     "this_binding to caller's this_binding");
 
20416
 
 
20417
                        act = thr->callstack + thr->callstack_top - 2;  /* caller */
 
20418
                        act_lex_env = act->lex_env;
 
20419
                        act = NULL;  /* invalidated */
 
20420
 
 
20421
                        (void) duk_push_object_helper_proto(ctx,
 
20422
                                                            DUK_HOBJECT_FLAG_EXTENSIBLE |
 
20423
                                                            DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
 
20424
                                                            act_lex_env);
 
20425
                        new_env = duk_require_hobject(ctx, -1);
 
20426
                        DUK_ASSERT(new_env != NULL);
 
20427
                        DUK_DDDPRINT("new_env allocated: %!iO", new_env);
 
20428
 
 
20429
                        outer_lex_env = new_env;
 
20430
                        outer_var_env = new_env;
 
20431
 
 
20432
                        duk_insert(ctx, 0);  /* stash to bottom of value stack to keep new_env reachable */
 
20433
 
 
20434
                        /* compiler's responsibility */
 
20435
                        DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
 
20436
                } else {
 
20437
                        DUK_DDDPRINT("direct eval call to a non-strict function -> "
 
20438
                                     "var_env and lex_env to caller's envs, "
 
20439
                                     "this_binding to caller's this_binding");
 
20440
 
 
20441
                        outer_lex_env = act->lex_env;
 
20442
                        outer_var_env = act->var_env;
 
20443
 
 
20444
                        /* compiler's responsibility */
 
20445
                        DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
 
20446
                }
 
20447
        } else {
 
20448
                DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
 
20449
                             "global object, this_binding to global object");
 
20450
 
 
20451
                this_to_global = 1;
 
20452
                outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
20453
                outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
20454
        }
 
20455
        act = NULL;
 
20456
 
 
20457
        duk_js_push_closure(thr, func, outer_var_env, outer_lex_env);
 
20458
 
 
20459
        if (this_to_global) {
 
20460
                DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
 
20461
                duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
 
20462
        } else {
 
20463
                duk_tval *tv;
 
20464
                DUK_ASSERT(thr->callstack_top >= 2);
 
20465
                act = thr->callstack + thr->callstack_top - 2;  /* caller */
 
20466
                tv = thr->valstack + act->idx_bottom - 1;  /* this is just beneath bottom */
 
20467
                DUK_ASSERT(tv >= thr->valstack);
 
20468
                duk_push_tval(ctx, tv);
 
20469
        }
 
20470
 
 
20471
        DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
 
20472
                     outer_lex_env, outer_var_env, duk_get_tval(ctx, -1));
 
20473
 
 
20474
        duk_call_method(ctx, 0);
 
20475
 
 
20476
        return 1;
 
20477
}
 
20478
 
 
20479
/*
 
20480
 *  Parsing of ints and floats
 
20481
 */
 
20482
 
 
20483
int duk_bi_global_object_parse_int(duk_context *ctx) {
 
20484
        int strip_prefix;
 
20485
        duk_int32_t radix;
 
20486
        int s2n_flags;
 
20487
 
 
20488
        DUK_ASSERT_TOP(ctx, 2);
 
20489
        duk_to_string(ctx, 0);
 
20490
 
 
20491
        strip_prefix = 1;
 
20492
        radix = duk_to_int32(ctx, 1);
 
20493
        if (radix != 0) {
 
20494
                if (radix < 2 || radix > 36) {
 
20495
                        goto ret_nan;
 
20496
                }
 
20497
                /* FIXME: how should octal behave here? */
 
20498
                if (radix != 16) {
 
20499
                        strip_prefix = 0;
 
20500
                }
 
20501
        } else {
 
20502
                radix = 10;
 
20503
        }
 
20504
 
 
20505
        s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
 
20506
                    DUK_S2N_FLAG_ALLOW_GARBAGE |
 
20507
                    DUK_S2N_FLAG_ALLOW_PLUS |
 
20508
                    DUK_S2N_FLAG_ALLOW_MINUS |
 
20509
                    DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
 
20510
#ifdef DUK_USE_OCTAL_SUPPORT
 
20511
                    (strip_prefix ? DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT : 0) |
 
20512
#endif
 
20513
                    (strip_prefix ? DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT : 0);
 
20514
 
 
20515
        duk_dup(ctx, 0);
 
20516
        duk_numconv_parse(ctx, radix, s2n_flags);
 
20517
        return 1;
 
20518
 
 
20519
 ret_nan:
 
20520
        duk_push_nan(ctx);
 
20521
        return 1;
 
20522
}
 
20523
 
 
20524
int duk_bi_global_object_parse_float(duk_context *ctx) {
 
20525
        int s2n_flags;
 
20526
 
 
20527
        DUK_ASSERT_TOP(ctx, 1);
 
20528
        duk_to_string(ctx, 0);
 
20529
 
 
20530
        /* FIXME: flags */
 
20531
        s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
 
20532
                    DUK_S2N_FLAG_ALLOW_EXP |
 
20533
                    DUK_S2N_FLAG_ALLOW_GARBAGE |
 
20534
                    DUK_S2N_FLAG_ALLOW_PLUS |
 
20535
                    DUK_S2N_FLAG_ALLOW_MINUS |
 
20536
                    DUK_S2N_FLAG_ALLOW_INF |
 
20537
                    DUK_S2N_FLAG_ALLOW_FRAC |
 
20538
                    DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
 
20539
                    DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
 
20540
                    DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
 
20541
 
 
20542
        duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
 
20543
        return 1;
 
20544
}
 
20545
 
 
20546
/*
 
20547
 *  Number checkers
 
20548
 */
 
20549
int duk_bi_global_object_is_nan(duk_context *ctx) {
 
20550
        double d = duk_to_number(ctx, 0);
 
20551
        duk_push_boolean(ctx, DUK_ISNAN(d));
 
20552
        return 1;
 
20553
}
 
20554
 
 
20555
int duk_bi_global_object_is_finite(duk_context *ctx) {
 
20556
        double d = duk_to_number(ctx, 0);
 
20557
        duk_push_boolean(ctx, DUK_ISFINITE(d));
 
20558
        return 1;
 
20559
}
 
20560
 
 
20561
/*
 
20562
 *  URI handling
 
20563
 */
 
20564
 
 
20565
int duk_bi_global_object_decode_uri(duk_context *ctx) {
 
20566
        return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_reserved_table);
 
20567
}
 
20568
 
 
20569
int duk_bi_global_object_decode_uri_component(duk_context *ctx) {
 
20570
        return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (void *) duk__decode_uri_component_reserved_table);
 
20571
}
 
20572
 
 
20573
int duk_bi_global_object_encode_uri(duk_context *ctx) {
 
20574
        return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uriunescaped_table);
 
20575
}
 
20576
 
 
20577
int duk_bi_global_object_encode_uri_component(duk_context *ctx) {
 
20578
        return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (void *) duk__encode_uricomponent_unescaped_table);
 
20579
}
 
20580
 
 
20581
#ifdef DUK_USE_SECTION_B
 
20582
int duk_bi_global_object_escape(duk_context *ctx) {
 
20583
        return duk__transform_helper(ctx, duk__transform_callback_escape, (void *) NULL);
 
20584
}
 
20585
 
 
20586
int duk_bi_global_object_unescape(duk_context *ctx) {
 
20587
        return duk__transform_helper(ctx, duk__transform_callback_unescape, (void *) NULL);
 
20588
}
 
20589
#else  /* DUK_USE_SECTION_B */
 
20590
int duk_bi_global_object_escape(duk_context *ctx) {
 
20591
        DUK_UNREF(ctx);
 
20592
        return DUK_RET_UNSUPPORTED_ERROR;
 
20593
}
 
20594
 
 
20595
int duk_bi_global_object_unescape(duk_context *ctx) {
 
20596
        DUK_UNREF(ctx);
 
20597
        return DUK_RET_UNSUPPORTED_ERROR;
 
20598
}
 
20599
#endif  /* DUK_USE_SECTION_B */
 
20600
 
 
20601
#ifdef DUK_USE_BROWSER_LIKE
 
20602
#ifdef DUK_USE_FILE_IO
 
20603
static int duk__print_alert_helper(duk_context *ctx, duk_file *f_out) {
 
20604
        int nargs;
 
20605
        int i;
 
20606
        const char *str;
 
20607
        size_t len;
 
20608
        char nl = '\n';
 
20609
 
 
20610
        /* If argument count is 1 and first argument is a buffer, write the buffer
 
20611
         * as raw data into the file without a newline; this allows exact control
 
20612
         * over stdout/stderr without an additional entrypoint (useful for now).
 
20613
         */
 
20614
 
 
20615
        nargs = duk_get_top(ctx);
 
20616
        if (nargs == 1 && duk_is_buffer(ctx, 0)) {
 
20617
                const char *buf = NULL;
 
20618
                size_t sz = 0;
 
20619
                buf = (const char *) duk_get_buffer(ctx, 0, &sz);
 
20620
                if (buf && sz > 0) {
 
20621
                        DUK_FWRITE(buf, 1, sz, f_out);
 
20622
                }
 
20623
                goto flush;
 
20624
        }
 
20625
 
 
20626
        /* FIXME: best semantics link?  Now apply ToString to args, join with ' ' */
 
20627
        /* FIXME: ToString() coerce inplace instead? */
 
20628
 
 
20629
        if (nargs > 0) {
 
20630
                for (i = 0; i < nargs; i++) {
 
20631
                        if (i != 0) {
 
20632
                                duk_push_hstring_stridx(ctx, DUK_STRIDX_SPACE);
 
20633
                        }
 
20634
                        duk_dup(ctx, i);
 
20635
                        duk_to_string(ctx, -1);
 
20636
                }
 
20637
 
 
20638
                duk_concat(ctx, 2*nargs - 1);
 
20639
 
 
20640
                str = duk_get_lstring(ctx, -1, &len);
 
20641
                if (str) {
 
20642
                        DUK_FWRITE(str, 1, len, f_out);
 
20643
                }
 
20644
        }
 
20645
 
 
20646
        DUK_FWRITE(&nl, 1, 1, f_out);
 
20647
 
 
20648
 flush:
 
20649
        DUK_FFLUSH(f_out);
 
20650
        return 0;
 
20651
}
 
20652
 
 
20653
int duk_bi_global_object_print(duk_context *ctx) {
 
20654
        return duk__print_alert_helper(ctx, DUK_STDOUT);
 
20655
}
 
20656
 
 
20657
int duk_bi_global_object_alert(duk_context *ctx) {
 
20658
        return duk__print_alert_helper(ctx, DUK_STDERR);
 
20659
}
 
20660
#else  /* DUK_USE_FILE_IO */
 
20661
/* Supported but no file I/O -> silently ignore, no error */
 
20662
int duk_bi_global_object_print(duk_context *ctx) {
 
20663
        return 0;
 
20664
}
 
20665
 
 
20666
int duk_bi_global_object_alert(duk_context *ctx) {
 
20667
        return 0;
 
20668
}
 
20669
#endif  /* DUK_USE_FILE_IO */
 
20670
#else  /* DUK_USE_BROWSER_LIKE */
 
20671
int duk_bi_global_object_print(duk_context *ctx) {
 
20672
        DUK_UNREF(ctx);
 
20673
        return DUK_RET_UNSUPPORTED_ERROR;
 
20674
}
 
20675
 
 
20676
int duk_bi_global_object_alert(duk_context *ctx) {
 
20677
        DUK_UNREF(ctx);
 
20678
        return DUK_RET_UNSUPPORTED_ERROR;
 
20679
}
 
20680
#endif  /* DUK_USE_BROWSER_LIKE */
 
20681
#line 1 "duk_bi_json.c"
 
20682
/*
 
20683
 *  JSON built-ins.
 
20684
 *
 
20685
 *  See doc/json.txt.
 
20686
 */
 
20687
 
 
20688
/* include removed: duk_internal.h */
 
20689
 
 
20690
/*
 
20691
 *  Local defines and forward declarations.
 
20692
 */
 
20693
 
 
20694
static void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
 
20695
static void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
 
20696
static int duk__dec_peek(duk_json_dec_ctx *js_ctx);
 
20697
static int duk__dec_get(duk_json_dec_ctx *js_ctx);
 
20698
static int duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
 
20699
static duk_uint32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, int n);
 
20700
static void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, int stridx);
 
20701
static void duk__dec_string(duk_json_dec_ctx *js_ctx);
 
20702
#ifdef DUK_USE_JSONX
 
20703
static void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
 
20704
static void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
 
20705
static void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
 
20706
#endif
 
20707
static void duk__dec_number(duk_json_dec_ctx *js_ctx);
 
20708
static void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
 
20709
static void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
 
20710
static void duk__dec_object(duk_json_dec_ctx *js_ctx);
 
20711
static void duk__dec_array(duk_json_dec_ctx *js_ctx);
 
20712
static void duk__dec_value(duk_json_dec_ctx *js_ctx);
 
20713
static void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
 
20714
 
 
20715
static void duk__emit_1(duk_json_enc_ctx *js_ctx, char ch);
 
20716
static void duk__emit_2(duk_json_enc_ctx *js_ctx, int chars);
 
20717
static void duk__emit_esc_auto(duk_json_enc_ctx *js_ctx, duk_uint32_t cp);
 
20718
static void duk__emit_xutf8(duk_json_enc_ctx *js_ctx, duk_uint32_t cp);
 
20719
static void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
 
20720
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
20721
static void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
 
20722
#endif
 
20723
static int duk__enc_key_quotes_needed(duk_hstring *h_key);
 
20724
static void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
 
20725
static void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, int *entry_top);
 
20726
static void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, int *entry_top);
 
20727
static void duk__enc_object(duk_json_enc_ctx *js_ctx);
 
20728
static void duk__enc_array(duk_json_enc_ctx *js_ctx);
 
20729
static int duk__enc_value1(duk_json_enc_ctx *js_ctx, int idx_holder);
 
20730
static void duk__enc_value2(duk_json_enc_ctx *js_ctx);
 
20731
static int duk__enc_allow_into_proplist(duk_tval *tv);
 
20732
 
 
20733
/*
 
20734
 *  Parsing implementation.
 
20735
 *
 
20736
 *  JSON lexer is now separate from duk_lexer.c because there are numerous
 
20737
 *  small differences making it difficult to share the lexer.
 
20738
 *
 
20739
 *  The parser here works with raw bytes directly; this works because all
 
20740
 *  JSON delimiters are ASCII characters.  Invalid xUTF-8 encoded values
 
20741
 *  inside strings will be passed on without normalization; this is not a
 
20742
 *  compliance concern because compliant inputs will always be valid
 
20743
 *  CESU-8 encodings.
 
20744
 */
 
20745
 
 
20746
static void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
 
20747
        /* Shared handler to minimize parser size.  Cause will be
 
20748
         * hidden, unfortunately.
 
20749
         */
 
20750
        DUK_ERROR(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, "invalid json");
 
20751
}
 
20752
 
 
20753
static void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
 
20754
        int t;
 
20755
        for (;;) {
 
20756
                if (js_ctx->p >= js_ctx->p_end) {
 
20757
                        break;
 
20758
                }
 
20759
                t = (int) (*js_ctx->p);
 
20760
                if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
 
20761
                        break;
 
20762
                }
 
20763
                js_ctx->p++;
 
20764
        }
 
20765
}
 
20766
 
 
20767
static int duk__dec_peek(duk_json_dec_ctx *js_ctx) {
 
20768
        if (js_ctx->p >= js_ctx->p_end) {
 
20769
                return -1;
 
20770
        } else {
 
20771
                return (int) (*js_ctx->p);
 
20772
        }
 
20773
}
 
20774
 
 
20775
static int duk__dec_get(duk_json_dec_ctx *js_ctx) {
 
20776
        /* Multiple EOFs will now be supplied to the caller.  This could also be
 
20777
         * changed so that reading the second EOF would cause an error automatically.
 
20778
         */
 
20779
        if (js_ctx->p >= js_ctx->p_end) {
 
20780
                return -1;
 
20781
        } else {
 
20782
                return (int) (*js_ctx->p++);
 
20783
        }
 
20784
}
 
20785
 
 
20786
static int duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
 
20787
        duk__dec_eat_white(js_ctx);
 
20788
        return duk__dec_get(js_ctx);
 
20789
}
 
20790
 
 
20791
static duk_uint32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, int n) {
 
20792
        int i;
 
20793
        duk_uint32_t res = 0;
 
20794
        int x;
 
20795
 
 
20796
        for (i = 0; i < n; i++) {
 
20797
                /* FIXME: share helper from lexer; duk_lexer.c / hexval(). */
 
20798
 
 
20799
                x = duk__dec_get(js_ctx);
 
20800
 
 
20801
                DUK_DDDPRINT("decode_hex_escape: i=%d, n=%d, res=%d, x=%d",
 
20802
                             i, n, (int) res, x);
 
20803
 
 
20804
                res *= 16;
 
20805
                if (x >= (int) '0' && x <= (int) '9') {
 
20806
                        res += x - (int) '0';
 
20807
                } else if (x >= 'a' && x <= 'f') {
 
20808
                        res += x - (int) 'a' + 0x0a;
 
20809
                } else if (x >= 'A' && x <= 'F') {
 
20810
                        res += x - (int) 'A' + 0x0a;
 
20811
                } else {
 
20812
                        /* catches EOF */
 
20813
                        goto syntax_error;
 
20814
                }
 
20815
        }
 
20816
 
 
20817
        DUK_DDDPRINT("final hex decoded value: %d", (int) res);
 
20818
        return res;
 
20819
 
 
20820
 syntax_error:
 
20821
        duk__dec_syntax_error(js_ctx);
 
20822
        DUK_UNREACHABLE();
 
20823
        return 0;
 
20824
}
 
20825
 
 
20826
static void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, int stridx) {
 
20827
        duk_hstring *h;
 
20828
        duk_uint8_t *p;
 
20829
        duk_uint8_t *p_end;
 
20830
        int x;
 
20831
 
 
20832
        /* First character has already been eaten and checked by the
 
20833
         * caller.
 
20834
         */
 
20835
 
 
20836
        DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
 
20837
        h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
 
20838
        DUK_ASSERT(h != NULL);
 
20839
 
 
20840
        p = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
 
20841
        p_end = ((duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) +
 
20842
                DUK_HSTRING_GET_BYTELEN(h);
 
20843
 
 
20844
        DUK_ASSERT((int) *(js_ctx->p - 1) == (int) *p);
 
20845
        p++;  /* first char */
 
20846
 
 
20847
        while (p < p_end) {
 
20848
                x = duk__dec_get(js_ctx);
 
20849
                if ((int) (*p) != x) {
 
20850
                        /* catches EOF */
 
20851
                        goto syntax_error;
 
20852
                }
 
20853
                p++;
 
20854
        }
 
20855
 
 
20856
        return;
 
20857
 
 
20858
 syntax_error:
 
20859
        duk__dec_syntax_error(js_ctx);
 
20860
        DUK_UNREACHABLE();
 
20861
}
 
20862
 
 
20863
static void duk__dec_string(duk_json_dec_ctx *js_ctx) {
 
20864
        duk_hthread *thr = js_ctx->thr;
 
20865
        duk_context *ctx = (duk_context *) thr;
 
20866
        duk_hbuffer_dynamic *h_buf;
 
20867
        int x;
 
20868
 
 
20869
        /* '"' was eaten by caller */
 
20870
 
 
20871
        /* Note that we currently parse -bytes-, not codepoints.
 
20872
         * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
 
20873
         * so they'll simply pass through (valid UTF-8 or not).
 
20874
         */
 
20875
 
 
20876
        duk_push_dynamic_buffer(ctx, 0);
 
20877
        h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
20878
        DUK_ASSERT(h_buf != NULL);
 
20879
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf));
 
20880
 
 
20881
        for (;;) {
 
20882
                x = duk__dec_get(js_ctx);
 
20883
                if (x == (int) '"') {
 
20884
                        break;
 
20885
                } else if (x == (int) '\\') {
 
20886
                        x = duk__dec_get(js_ctx);
 
20887
                        switch (x) {
 
20888
                        case '\\': break;
 
20889
                        case '"': break;
 
20890
                        case '/': break;
 
20891
                        case 't': x = 0x09; break;
 
20892
                        case 'n': x = 0x0a; break;
 
20893
                        case 'r': x = 0x0d; break;
 
20894
                        case 'f': x = 0x0c; break;
 
20895
                        case 'b': x = 0x08; break;
 
20896
                        case 'u': {
 
20897
                                x = duk__dec_decode_hex_escape(js_ctx, 4);
 
20898
                                break;
 
20899
                        }
 
20900
#ifdef DUK_USE_JSONX
 
20901
                        case 'U': {
 
20902
                                if (js_ctx->flag_ext_custom) {
 
20903
                                        x = duk__dec_decode_hex_escape(js_ctx, 8);
 
20904
                                } else {
 
20905
                                        goto syntax_error;
 
20906
                                }
 
20907
                                break;
 
20908
                        }
 
20909
                        case 'x': {
 
20910
                                if (js_ctx->flag_ext_custom) {
 
20911
                                        x = duk__dec_decode_hex_escape(js_ctx, 2);
 
20912
                                } else {
 
20913
                                        goto syntax_error;
 
20914
                                }
 
20915
                                break;
 
20916
                        }
 
20917
#endif  /* DUK_USE_JSONX */
 
20918
                        default:
 
20919
                                goto syntax_error;
 
20920
                        }
 
20921
                        duk_hbuffer_append_xutf8(thr, h_buf, (duk_uint32_t) x);
 
20922
                } else if (x < 0x20) {
 
20923
                        /* catches EOF (-1) */
 
20924
                        goto syntax_error;
 
20925
                } else {
 
20926
                        duk_hbuffer_append_byte(thr, h_buf, (duk_uint8_t) x);
 
20927
                }
 
20928
        }
 
20929
 
 
20930
        duk_to_string(ctx, -1);
 
20931
 
 
20932
        /* [ ... str ] */
 
20933
 
 
20934
        return;
 
20935
 
 
20936
 syntax_error:
 
20937
        duk__dec_syntax_error(js_ctx);
 
20938
        DUK_UNREACHABLE();
 
20939
}
 
20940
 
 
20941
#ifdef DUK_USE_JSONX
 
20942
/* Decode a plain string consisting entirely of identifier characters.
 
20943
 * Used to parse plain keys (e.g. "foo: 123").
 
20944
 */
 
20945
static void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
 
20946
        duk_hthread *thr = js_ctx->thr;
 
20947
        duk_context *ctx = (duk_context *) thr;
 
20948
        duk_uint8_t *p;
 
20949
        duk_small_int_t x;
 
20950
 
 
20951
        /* Caller has already eaten the first character so backtrack one
 
20952
         * byte.
 
20953
         */
 
20954
 
 
20955
        js_ctx->p--;  /* safe */
 
20956
        p = js_ctx->p;
 
20957
 
 
20958
        /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
 
20959
         * parsing (which is correct except if there are non-shortest encodings).
 
20960
         * There is also no need to check explicitly for end of input buffer as
 
20961
         * the input is NUL padded and NUL will exit the parsing loop.
 
20962
         *
 
20963
         * Because no unescaping takes place, we can just scan to the end of the
 
20964
         * plain string and intern from the input buffer.
 
20965
         */
 
20966
 
 
20967
        for (;;) {
 
20968
                x = *p;
 
20969
 
 
20970
                /* There is no need to check the first character specially here
 
20971
                 * (i.e. reject digits): the caller only accepts valid initial
 
20972
                 * characters and won't call us if the first character is a digit.
 
20973
                 * This also ensures that the plain string won't be empty.
 
20974
                 */
 
20975
 
 
20976
                if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
 
20977
                        break;
 
20978
                }
 
20979
                p++;
 
20980
        }
 
20981
 
 
20982
        duk_push_lstring(ctx, (const char *) js_ctx->p, (size_t) (p - js_ctx->p));
 
20983
        js_ctx->p = p;
 
20984
 
 
20985
        /* [ ... str ] */
 
20986
}
 
20987
#endif  /* DUK_USE_JSONX */
 
20988
 
 
20989
#ifdef DUK_USE_JSONX
 
20990
static void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
 
20991
        duk_hthread *thr = js_ctx->thr;
 
20992
        duk_context *ctx = (duk_context *) thr;
 
20993
        duk_uint8_t *p;
 
20994
        duk_small_int_t x;
 
20995
        void *voidptr;
 
20996
 
 
20997
        /* Caller has already eaten the first character ('(') which we don't need. */
 
20998
 
 
20999
        p = js_ctx->p;
 
21000
 
 
21001
        for (;;) {
 
21002
                x = *p;
 
21003
 
 
21004
                /* Assume that the native representation never contains a closing
 
21005
                 * parenthesis.
 
21006
                 */
 
21007
 
 
21008
                if (x == ')') {
 
21009
                        break;
 
21010
                } else if (x <= 0) {
 
21011
                        /* NUL term or -1 (EOF), NUL check would suffice */
 
21012
                        goto syntax_error;
 
21013
                }
 
21014
                p++;
 
21015
        }
 
21016
 
 
21017
        /* There is no need to delimit the scanning call: trailing garbage is
 
21018
         * ignored and there is always a NUL terminator which will force an error
 
21019
         * if no error is encountered before it.  It's possible that the scan
 
21020
         * would scan further than between [js_ctx->p,p[ though and we'd advance
 
21021
         * by less than the scanned value.
 
21022
         *
 
21023
         * Because pointers are platform specific, a failure to scan a pointer
 
21024
         * results in a null pointer which is a better placeholder than a missing
 
21025
         * value or an error.
 
21026
         */
 
21027
 
 
21028
        voidptr = NULL;
 
21029
        (void) DUK_SSCANF((const char *) js_ctx->p, "%p", &voidptr);
 
21030
        duk_push_pointer(ctx, voidptr);
 
21031
        js_ctx->p = p + 1;  /* skip ')' */
 
21032
 
 
21033
        /* [ ... ptr ] */
 
21034
 
 
21035
        return;
 
21036
 
 
21037
 syntax_error:
 
21038
        duk__dec_syntax_error(js_ctx);
 
21039
        DUK_UNREACHABLE();
 
21040
}
 
21041
#endif  /* DUK_USE_JSONX */
 
21042
 
 
21043
#ifdef DUK_USE_JSONX
 
21044
static void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
 
21045
        duk_hthread *thr = js_ctx->thr;
 
21046
        duk_context *ctx = (duk_context *) thr;
 
21047
        duk_uint8_t *p;
 
21048
        duk_small_int_t x;
 
21049
 
 
21050
        /* Caller has already eaten the first character ('|') which we don't need. */
 
21051
 
 
21052
        p = js_ctx->p;
 
21053
 
 
21054
        for (;;) {
 
21055
                x = *p;
 
21056
 
 
21057
                /* This loop intentionally does not ensure characters are valid
 
21058
                 * ([0-9a-fA-F]) because the hex decode call below will do that.
 
21059
                 */
 
21060
                if (x == '|') {
 
21061
                        break;
 
21062
                } else if (x <= 0) {
 
21063
                        /* NUL term or -1 (EOF), NUL check would suffice */
 
21064
                        goto syntax_error;
 
21065
                }
 
21066
                p++;
 
21067
        }
 
21068
 
 
21069
        duk_push_lstring(ctx, (const char *) js_ctx->p, (size_t) (p - js_ctx->p));
 
21070
        duk_hex_decode(ctx, -1);
 
21071
        js_ctx->p = p + 1;  /* skip '|' */
 
21072
 
 
21073
        /* [ ... buf ] */
 
21074
 
 
21075
        return;
 
21076
 
 
21077
 syntax_error:
 
21078
        duk__dec_syntax_error(js_ctx);
 
21079
        DUK_UNREACHABLE();
 
21080
}
 
21081
#endif  /* DUK_USE_JSONX */
 
21082
 
 
21083
/* Parse a number, other than NaN or +/- Infinity */
 
21084
static void duk__dec_number(duk_json_dec_ctx *js_ctx) {
 
21085
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21086
        duk_uint8_t *p_start;
 
21087
        int x;
 
21088
        int s2n_flags;
 
21089
 
 
21090
        DUK_DDDPRINT("parse_number");
 
21091
 
 
21092
        /* Caller has already eaten the first character so backtrack one
 
21093
         * byte.  This is correct because the first character is either
 
21094
         * '-' or a digit (i.e. an ASCII character).
 
21095
         */
 
21096
 
 
21097
        js_ctx->p--;  /* safe */
 
21098
        p_start = js_ctx->p;
 
21099
 
 
21100
        /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
 
21101
         * string for strict number parsing.
 
21102
         */
 
21103
 
 
21104
        for (;;) {
 
21105
                x = duk__dec_peek(js_ctx);
 
21106
 
 
21107
                DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%d",
 
21108
                             (void *) p_start, (void *) js_ctx->p,
 
21109
                             (void *) js_ctx->p_end, x);
 
21110
 
 
21111
                if (!((x >= (int) '0' && x <= (int) '9') ||
 
21112
                      (x == '.' || x == 'e' || x == 'E' || x == '-'))) {
 
21113
                        break;
 
21114
                }
 
21115
 
 
21116
                js_ctx->p++;  /* safe, because matched char */
 
21117
        }
 
21118
 
 
21119
        DUK_ASSERT(js_ctx->p > p_start);
 
21120
        duk_push_lstring(ctx, (const char *) p_start, (size_t) (js_ctx->p - p_start));
 
21121
 
 
21122
        s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
 
21123
                    DUK_S2N_FLAG_ALLOW_MINUS |  /* but don't allow leading plus */
 
21124
                    DUK_S2N_FLAG_ALLOW_FRAC;
 
21125
 
 
21126
        DUK_DDDPRINT("parse_number: string before parsing: %!T", duk_get_tval(ctx, -1));
 
21127
        duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
 
21128
        if (duk_is_nan(ctx, -1)) {
 
21129
                DUK_ERROR(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, "invalid number");
 
21130
        }
 
21131
        DUK_ASSERT(duk_is_number(ctx, -1));
 
21132
        DUK_DDDPRINT("parse_number: final number: %!T", duk_get_tval(ctx, -1));
 
21133
 
 
21134
        /* [ ... num ] */
 
21135
}
 
21136
 
 
21137
static void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
 
21138
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21139
        duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
 
21140
 
 
21141
        /* c recursion check */
 
21142
 
 
21143
        DUK_ASSERT(js_ctx->recursion_depth >= 0);
 
21144
        DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 
21145
        if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
 
21146
                DUK_ERROR((duk_hthread *) ctx, DUK_ERR_RANGE_ERROR, "json decode recursion limit");
 
21147
        }
 
21148
        js_ctx->recursion_depth++;
 
21149
}
 
21150
 
 
21151
static void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
 
21152
        /* c recursion check */
 
21153
 
 
21154
        DUK_ASSERT(js_ctx->recursion_depth > 0);
 
21155
        DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 
21156
        js_ctx->recursion_depth--;
 
21157
}
 
21158
 
 
21159
static void duk__dec_object(duk_json_dec_ctx *js_ctx) {
 
21160
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21161
        int key_count;
 
21162
        int x;
 
21163
 
 
21164
        DUK_DDDPRINT("parse_object");
 
21165
 
 
21166
        duk__dec_objarr_entry(js_ctx);
 
21167
 
 
21168
        duk_push_object(ctx);
 
21169
 
 
21170
        /* Initial '{' has been checked and eaten by caller. */
 
21171
 
 
21172
        key_count = 0;
 
21173
        for (;;) {
 
21174
                x = duk__dec_get_nonwhite(js_ctx);
 
21175
 
 
21176
                DUK_DDDPRINT("parse_object: obj=%!T, x=%d, key_count=%d",
 
21177
                           duk_get_tval(ctx, -1), x, key_count);
 
21178
 
 
21179
                /* handle comma and closing brace */
 
21180
 
 
21181
                if (x == (int) ',' && key_count > 0) {
 
21182
                        /* accept comma, expect new value */
 
21183
                        x = duk__dec_get_nonwhite(js_ctx);
 
21184
                } else if (x == (int) '}') {
 
21185
                        /* eat closing brace */
 
21186
                        break;
 
21187
                } else if (key_count == 0) {
 
21188
                        /* accept anything, expect first value (EOF will be
 
21189
                         * caught by key parsing below.
 
21190
                         */
 
21191
                        ;
 
21192
                } else {
 
21193
                        /* catches EOF (and initial comma) */
 
21194
                        goto syntax_error;
 
21195
                }
 
21196
 
 
21197
                /* parse key and value */
 
21198
 
 
21199
                if (x == (int) '"') {
 
21200
                        duk__dec_string(js_ctx);
 
21201
#ifdef DUK_USE_JSONX
 
21202
                } else if (js_ctx->flag_ext_custom &&
 
21203
                           duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
 
21204
                        duk__dec_plain_string(js_ctx);
 
21205
#endif
 
21206
                } else {
 
21207
                        goto syntax_error;
 
21208
                }
 
21209
 
 
21210
                /* [ ... obj key ] */
 
21211
 
 
21212
                x = duk__dec_get_nonwhite(js_ctx);
 
21213
                if (x != (int) ':') {
 
21214
                        goto syntax_error;
 
21215
                }
 
21216
 
 
21217
                duk__dec_value(js_ctx);
 
21218
 
 
21219
                /* [ ... obj key val ] */
 
21220
 
 
21221
                duk_put_prop(ctx, -3);
 
21222
 
 
21223
                /* [ ... obj ] */
 
21224
 
 
21225
                key_count++;
 
21226
        }
 
21227
 
 
21228
        /* [ ... obj ] */
 
21229
 
 
21230
        DUK_DDDPRINT("parse_object: final object is %!T", duk_get_tval(ctx, -1));
 
21231
 
 
21232
        duk__dec_objarr_exit(js_ctx);
 
21233
        return;
 
21234
 
 
21235
 syntax_error:
 
21236
        duk__dec_syntax_error(js_ctx);
 
21237
        DUK_UNREACHABLE();
 
21238
}
 
21239
 
 
21240
static void duk__dec_array(duk_json_dec_ctx *js_ctx) {
 
21241
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21242
        int arr_idx;
 
21243
        int x;
 
21244
 
 
21245
        DUK_DDDPRINT("parse_array");
 
21246
 
 
21247
        duk__dec_objarr_entry(js_ctx);
 
21248
 
 
21249
        duk_push_array(ctx);
 
21250
 
 
21251
        /* Initial '[' has been checked and eaten by caller. */
 
21252
 
 
21253
        arr_idx = 0;
 
21254
        for (;;) {
 
21255
                x = duk__dec_get_nonwhite(js_ctx);
 
21256
 
 
21257
                DUK_DDDPRINT("parse_array: arr=%!T, x=%d, arr_idx=%d",
 
21258
                             duk_get_tval(ctx, -1), x, arr_idx);
 
21259
 
 
21260
                /* handle comma and closing bracket */
 
21261
 
 
21262
                if ((x == ',') && (arr_idx != 0)) {
 
21263
                        /* accept comma, expect new value */
 
21264
                        ;
 
21265
                } else if (x == (int) ']') {
 
21266
                        /* eat closing bracket */
 
21267
                        break;
 
21268
                } else if (arr_idx == 0) {
 
21269
                        /* accept anything, expect first value (EOF will be
 
21270
                         * caught by duk__dec_value() below.
 
21271
                         */
 
21272
                        js_ctx->p--;  /* backtrack (safe) */
 
21273
                } else {
 
21274
                        /* catches EOF (and initial comma) */
 
21275
                        goto syntax_error;
 
21276
                }
 
21277
 
 
21278
                /* parse value */
 
21279
 
 
21280
                duk__dec_value(js_ctx);
 
21281
 
 
21282
                /* [ ... arr val ] */
 
21283
 
 
21284
                duk_put_prop_index(ctx, -2, arr_idx);
 
21285
                arr_idx++;
 
21286
        }
 
21287
 
 
21288
        /* [ ... arr ] */
 
21289
 
 
21290
        DUK_DDDPRINT("parse_array: final array is %!T", duk_get_tval(ctx, -1));
 
21291
 
 
21292
        duk__dec_objarr_exit(js_ctx);
 
21293
        return;
 
21294
 
 
21295
 syntax_error:
 
21296
        duk__dec_syntax_error(js_ctx);
 
21297
        DUK_UNREACHABLE();
 
21298
}
 
21299
 
 
21300
static void duk__dec_value(duk_json_dec_ctx *js_ctx) {
 
21301
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21302
        int x;
 
21303
 
 
21304
        x = duk__dec_get_nonwhite(js_ctx);
 
21305
 
 
21306
        DUK_DDDPRINT("parse_value: initial x=%d", x);
 
21307
 
 
21308
        /* Note: duk__dec_req_stridx() backtracks one char */
 
21309
 
 
21310
        if (x == (int) '"') {
 
21311
                duk__dec_string(js_ctx);
 
21312
        } else if ((x >= (int) '0' && x <= (int) '9') || (x == (int) '-')) {
 
21313
#ifdef DUK_USE_JSONX
 
21314
                if (js_ctx->flag_ext_custom && duk__dec_peek(js_ctx) == 'I') {
 
21315
                        duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY);  /* "-Infinity" */
 
21316
                        duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
 
21317
                } else {
 
21318
#else
 
21319
                {  /* unconditional block */
 
21320
#endif
 
21321
                        /* We already ate 'x', so duk__dec_number() will back up one byte. */
 
21322
                        duk__dec_number(js_ctx);
 
21323
                }
 
21324
        } else if (x == 't') {
 
21325
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
 
21326
                duk_push_true(ctx);
 
21327
        } else if (x == 'f') {
 
21328
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
 
21329
                duk_push_false(ctx);
 
21330
        } else if (x == 'n') {
 
21331
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_NULL);
 
21332
                duk_push_null(ctx);
 
21333
#ifdef DUK_USE_JSONX
 
21334
        } else if (js_ctx->flag_ext_custom && x == 'u') {
 
21335
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_UNDEFINED);
 
21336
                duk_push_undefined(ctx);
 
21337
        } else if (js_ctx->flag_ext_custom && x == 'N') {
 
21338
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
 
21339
                duk_push_nan(ctx);
 
21340
        } else if (js_ctx->flag_ext_custom && x == 'I') {
 
21341
                duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
 
21342
                duk_push_number(ctx, DUK_DOUBLE_INFINITY);
 
21343
        } else if (js_ctx->flag_ext_custom && x == '(') {
 
21344
                duk__dec_pointer(js_ctx);
 
21345
        } else if (js_ctx->flag_ext_custom && x == '|') {
 
21346
                duk__dec_buffer(js_ctx);
 
21347
#endif
 
21348
        } else if (x == '{') {
 
21349
                duk__dec_object(js_ctx);
 
21350
        } else if (x == '[') {
 
21351
                duk__dec_array(js_ctx);
 
21352
        } else {
 
21353
                /* catches EOF */
 
21354
                goto syntax_error;
 
21355
        }
 
21356
 
 
21357
        duk__dec_eat_white(js_ctx);
 
21358
 
 
21359
        /* [ ... val ] */
 
21360
        return;
 
21361
 
 
21362
 syntax_error:
 
21363
        duk__dec_syntax_error(js_ctx);
 
21364
        DUK_UNREACHABLE();
 
21365
}
 
21366
 
 
21367
/* Recursive value reviver, implements the Walk() algorithm.  No C recursion
 
21368
 * check is done here because the initial parsing step will already ensure
 
21369
 * there is a reasonable limit on C recursion depth and hence object depth.
 
21370
 */
 
21371
static void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
 
21372
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21373
        duk_hobject *h;
 
21374
        duk_uint_t i;
 
21375
        duk_uint_t arr_len;
 
21376
 
 
21377
        DUK_DDDPRINT("walk: top=%d, holder=%!T, name=%!T",
 
21378
                     duk_get_top(ctx), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
21379
 
 
21380
        duk_dup_top(ctx);
 
21381
        duk_get_prop(ctx, -3);  /* -> [ ... holder name val ] */
 
21382
 
 
21383
        h = duk_get_hobject(ctx, -1);
 
21384
        if (h != NULL) {
 
21385
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
 
21386
                        arr_len = duk_get_length(ctx, -1);
 
21387
                        for (i = 0; i < arr_len; i++) {
 
21388
                                /* [ ... holder name val ] */
 
21389
 
 
21390
                                DUK_DDDPRINT("walk: array, top=%d, i=%d, arr_len=%d, holder=%!T, name=%!T, val=%!T",
 
21391
                                             duk_get_top(ctx), i, arr_len, duk_get_tval(ctx, -3),
 
21392
                                             duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
21393
 
 
21394
                                /* FIXME: push_uint_string / push_u32_string */
 
21395
                                duk_dup_top(ctx);
 
21396
                                duk_push_number(ctx, (double) i);
 
21397
                                duk_to_string(ctx, -1);  /* -> [ ... holder name val val ToString(i) ] */
 
21398
                                duk__dec_reviver_walk(js_ctx);  /* -> [ ... holder name val new_elem ] */
 
21399
 
 
21400
                                if (duk_is_undefined(ctx, -1)) {
 
21401
                                        duk_pop(ctx);
 
21402
                                        duk_del_prop_index(ctx, -1, i);
 
21403
                                } else {
 
21404
                                        duk_put_prop_index(ctx, -2, i);
 
21405
                                }
 
21406
                        }
 
21407
                } else {
 
21408
                        /* [ ... holder name val ] */
 
21409
                        duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
 
21410
                        while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
 
21411
                                DUK_DDDPRINT("walk: object, top=%d, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
 
21412
                                             duk_get_top(ctx), duk_get_tval(ctx, -5),
 
21413
                                             duk_get_tval(ctx, -4), duk_get_tval(ctx, -3),
 
21414
                                             duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
21415
 
 
21416
                                /* [ ... holder name val enum obj_key ] */
 
21417
                                duk_dup(ctx, -3);
 
21418
                                duk_dup(ctx, -2);
 
21419
 
 
21420
                                /* [ ... holder name val enum obj_key val obj_key ] */
 
21421
                                duk__dec_reviver_walk(js_ctx);
 
21422
 
 
21423
                                /* [ ... holder name val enum obj_key new_elem ] */
 
21424
                                if (duk_is_undefined(ctx, -1)) {
 
21425
                                        duk_pop(ctx);
 
21426
                                        duk_del_prop(ctx, -3);
 
21427
                                } else {
 
21428
                                        duk_put_prop(ctx, -4);
 
21429
                                }
 
21430
                        }
 
21431
                        duk_pop(ctx);  /* pop enum */
 
21432
                }
 
21433
        }
 
21434
 
 
21435
        /* [ ... holder name val ] */
 
21436
 
 
21437
        duk_dup(ctx, js_ctx->idx_reviver);
 
21438
        duk_insert(ctx, -4);  /* -> [ ... reviver holder name val ] */
 
21439
        duk_call_method(ctx, 2);  /* -> [ ... res ] */
 
21440
 
 
21441
        DUK_DDDPRINT("walk: top=%d, result=%!T", duk_get_top(ctx), duk_get_tval(ctx, -1));
 
21442
}
 
21443
 
 
21444
/*
 
21445
 *  Stringify implementation.
 
21446
 */
 
21447
 
 
21448
#define DUK__EMIT_1(js_ctx,ch)          duk__emit_1((js_ctx),(ch))
 
21449
#define DUK__EMIT_2(js_ctx,ch1,ch2)     duk__emit_2((js_ctx),(((int)(ch1)) << 8) + (int)(ch2))
 
21450
#define DUK__EMIT_ESC_AUTO(js_ctx,cp)   duk__emit_esc_auto((js_ctx),(cp))
 
21451
#define DUK__EMIT_XUTF8(js_ctx,cp)      duk__emit_xutf8((js_ctx),(cp))
 
21452
#define DUK__EMIT_HSTR(js_ctx,h)        duk__emit_hstring((js_ctx),(h))
 
21453
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
21454
#define DUK__EMIT_CSTR(js_ctx,p)        duk__emit_cstring((js_ctx),(p))
 
21455
#endif
 
21456
#define DUK__EMIT_STRIDX(js_ctx,i)      duk__emit_stridx((js_ctx),(i))
 
21457
 
 
21458
static void duk__emit_1(duk_json_enc_ctx *js_ctx, char ch) {
 
21459
        duk_hbuffer_append_byte(js_ctx->thr, js_ctx->h_buf, (duk_uint8_t) ch);
 
21460
}
 
21461
 
 
21462
static void duk__emit_2(duk_json_enc_ctx *js_ctx, int chars) {
 
21463
        duk_uint8_t buf[2];
 
21464
        buf[0] = (chars >> 8);
 
21465
        buf[1] = chars & 0xff;
 
21466
        duk_hbuffer_append_bytes(js_ctx->thr, js_ctx->h_buf, (duk_uint8_t *) buf, 2);
 
21467
}
 
21468
 
 
21469
#define DUK__MKESC(nybbles,esc1,esc2)  \
 
21470
        (((duk_int_t) (nybbles)) << 16) | \
 
21471
        (((duk_int_t) (esc1)) << 8) | \
 
21472
        ((duk_int_t) (esc2))
 
21473
 
 
21474
static void duk__emit_esc_auto(duk_json_enc_ctx *js_ctx, duk_uint32_t cp) {
 
21475
        duk_uint8_t buf[2];
 
21476
        duk_int_t tmp;
 
21477
        duk_small_int_t dig;
 
21478
 
 
21479
        /* Select appropriate escape format automatically, and set 'tmp' to a
 
21480
         * value encoding both the escape format character and the nybble count:
 
21481
         *
 
21482
         *   (nybble_count << 16) | (escape_char1) | (escape_char2)
 
21483
         */
 
21484
 
 
21485
#ifdef DUK_USE_JSONX
 
21486
        if (DUK_LIKELY(cp < 0x100)) {
 
21487
                if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
 
21488
                        tmp = DUK__MKESC(2, '\\', 'x');
 
21489
                } else {
 
21490
                        tmp = DUK__MKESC(4, '\\', 'u');
 
21491
                }
 
21492
        } else
 
21493
#endif
 
21494
        if (DUK_LIKELY(cp < 0x10000)) {
 
21495
                tmp = DUK__MKESC(4, '\\', 'u');
 
21496
        } else {
 
21497
#ifdef DUK_USE_JSONX
 
21498
                if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
 
21499
                        tmp = DUK__MKESC(8, '\\', 'U');
 
21500
                } else
 
21501
#endif
 
21502
                {
 
21503
                        /* In compatible mode and standard JSON mode, output
 
21504
                         * something useful for non-BMP characters.  This won't
 
21505
                         * roundtrip but will still be more or less readable and
 
21506
                         * more useful than an error.
 
21507
                         */
 
21508
                        tmp = DUK__MKESC(8, 'U', '+');
 
21509
                }
 
21510
        }
 
21511
 
 
21512
        buf[0] = (duk_uint8_t) ((tmp >> 8) & 0xff);
 
21513
        buf[1] = (duk_uint8_t) (tmp & 0xff);
 
21514
        duk_hbuffer_append_bytes(js_ctx->thr, js_ctx->h_buf, buf, 2);
 
21515
 
 
21516
        tmp = tmp >> 16;
 
21517
        while (tmp > 0) {
 
21518
                tmp--;
 
21519
                dig = (cp >> (4 * tmp)) & 0x0f;
 
21520
                duk_hbuffer_append_byte(js_ctx->thr, js_ctx->h_buf, duk_lc_digits[dig]);
 
21521
        }
 
21522
}
 
21523
 
 
21524
static void duk__emit_xutf8(duk_json_enc_ctx *js_ctx, duk_uint32_t cp) {
 
21525
        (void) duk_hbuffer_append_xutf8(js_ctx->thr, js_ctx->h_buf, cp);
 
21526
}
 
21527
 
 
21528
static void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
 
21529
        DUK_ASSERT(h != NULL);
 
21530
        duk_hbuffer_append_bytes(js_ctx->thr,
 
21531
                                 js_ctx->h_buf,
 
21532
                                 (duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
 
21533
                                 (size_t) DUK_HSTRING_GET_BYTELEN(h));
 
21534
}
 
21535
 
 
21536
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
21537
static void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p) {
 
21538
        DUK_ASSERT(p != NULL);
 
21539
        (void) duk_hbuffer_append_cstring(js_ctx->thr, js_ctx->h_buf, p);
 
21540
}
 
21541
#endif
 
21542
 
 
21543
static void duk__emit_stridx(duk_json_enc_ctx *js_ctx, int stridx) {
 
21544
        DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
 
21545
        duk__emit_hstring(js_ctx, DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx));
 
21546
}
 
21547
 
 
21548
/* Check whether key quotes would be needed (custom encoding). */
 
21549
static int duk__enc_key_quotes_needed(duk_hstring *h_key) {
 
21550
        duk_uint8_t *p, *p_start, *p_end;
 
21551
        int ch;
 
21552
 
 
21553
        DUK_ASSERT(h_key != NULL);
 
21554
        p_start = DUK_HSTRING_GET_DATA(h_key);
 
21555
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_key);
 
21556
        p = p_start;
 
21557
 
 
21558
        DUK_DDDPRINT("duk__enc_key_quotes_needed: h_key=%!O, p_start=%p, p_end=%p, p=%p",
 
21559
                     (duk_heaphdr *) h_key, (void *) p_start, (void *) p_end, (void *) p);
 
21560
 
 
21561
        /* Since we only accept ASCII characters, there is no need for
 
21562
         * actual decoding.  A non-ASCII character will be >= 0x80 which
 
21563
         * causes a false return value immediately.
 
21564
         */
 
21565
 
 
21566
        if (p == p_end) {
 
21567
                /* Zero length string is not accepted without quotes */
 
21568
                return 1;
 
21569
        }
 
21570
 
 
21571
        while (p < p_end) {
 
21572
                ch = (int) (*p);
 
21573
 
 
21574
                /* Accept ASCII IdentifierStart and IdentifierPart if not first char.
 
21575
                 * Function selection is a bit uncommon.
 
21576
                 */
 
21577
                if ((p > p_start ? duk_unicode_is_identifier_part :
 
21578
                                   duk_unicode_is_identifier_start) ((duk_codepoint_t) ch)) {
 
21579
                        p++;
 
21580
                        continue;
 
21581
                }
 
21582
 
 
21583
                /* all non-ASCII characters also come here (first byte >= 0x80) */
 
21584
                return 1;
 
21585
        }
 
21586
 
 
21587
        return 0;
 
21588
}
 
21589
 
 
21590
/* The Quote(value) operation: quote a string.
 
21591
 *
 
21592
 * Stack policy: [ ] -> [ ].
 
21593
 */
 
21594
 
 
21595
static char duk__quote_esc[14] = {
 
21596
        '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
 
21597
        'b',  't',  'n',  '\0', 'f',  'r'
 
21598
};
 
21599
 
 
21600
static void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
 
21601
        duk_hthread *thr = js_ctx->thr;
 
21602
        duk_uint8_t *p, *p_start, *p_end, *p_tmp;
 
21603
        duk_ucodepoint_t cp;
 
21604
 
 
21605
        DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", h_str);
 
21606
 
 
21607
        DUK_ASSERT(h_str != NULL);
 
21608
        p_start = DUK_HSTRING_GET_DATA(h_str);
 
21609
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
 
21610
        p = p_start;
 
21611
 
 
21612
        DUK__EMIT_1(js_ctx, '"');
 
21613
 
 
21614
        while (p < p_end) {
 
21615
                cp = *p;
 
21616
 
 
21617
                if (cp <= 0x7f) {
 
21618
                        /* ascii fast path: avoid decoding utf-8 */
 
21619
                        p++;
 
21620
                        if (cp == 0x22 || cp == 0x5c) {
 
21621
                                /* double quote or backslash */
 
21622
                                DUK__EMIT_2(js_ctx, '\\', (char) cp);
 
21623
                        } else if (cp < 0x20) {
 
21624
                                char esc_char;
 
21625
 
 
21626
                                /* This approach is a bit shorter than a straight
 
21627
                                 * if-else-ladder and also a bit faster.
 
21628
                                 */
 
21629
                                if (cp < sizeof(duk__quote_esc) &&
 
21630
                                    (esc_char = duk__quote_esc[cp]) != (char) 0) {
 
21631
                                        DUK__EMIT_2(js_ctx, '\\', esc_char);
 
21632
                                } else {
 
21633
                                        DUK__EMIT_ESC_AUTO(js_ctx, cp);
 
21634
                                }
 
21635
                        } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
 
21636
                                DUK__EMIT_ESC_AUTO(js_ctx, cp);
 
21637
                        } else {
 
21638
                                /* any other printable -> as is */
 
21639
                                DUK__EMIT_1(js_ctx, (char) cp);
 
21640
                        }
 
21641
                } else {
 
21642
                        /* slow path decode */
 
21643
 
 
21644
                        /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
 
21645
                         * and go forward one byte.  This is of course very lossy, but allows some kind
 
21646
                         * of output to be produced even for internal strings which don't conform to
 
21647
                         * XUTF-8.  Note that all standard Ecmascript srings are always CESU-8, so this
 
21648
                         * behavior does not violate the Ecmascript specification.  The behavior is applied
 
21649
                         * to all modes, including Ecmascript standard JSON.  Because the current XUTF-8
 
21650
                         * decoding is not very strict, this behavior only really affects initial bytes
 
21651
                         * and truncated codepoints.
 
21652
                         *
 
21653
                         * XXX: another alternative would be to scan forwards to start of next codepoint
 
21654
                         * (or end of input) and emit just one replacement codepoint.
 
21655
                         */
 
21656
 
 
21657
                        p_tmp = p;
 
21658
                        if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
 
21659
                                /* Decode failed. */
 
21660
                                cp = *p_tmp;
 
21661
                                p = p_tmp + 1;
 
21662
                        }
 
21663
 
 
21664
                        if (js_ctx->flag_ascii_only) {
 
21665
                                DUK__EMIT_ESC_AUTO(js_ctx, cp);
 
21666
                        } else {
 
21667
                                /* as is */
 
21668
                                DUK__EMIT_XUTF8(js_ctx, cp);
 
21669
                        }
 
21670
                }
 
21671
        }
 
21672
 
 
21673
        DUK__EMIT_1(js_ctx, '"');
 
21674
}
 
21675
 
 
21676
/* Shared entry handling for object/array serialization: indent/stepback,
 
21677
 * loop detection.
 
21678
 */
 
21679
static void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, int *entry_top) {
 
21680
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21681
        duk_hobject *h_target;
 
21682
 
 
21683
        *entry_top = duk_get_top(ctx);
 
21684
 
 
21685
        duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
 
21686
 
 
21687
        /* loop check */
 
21688
 
 
21689
        h_target = duk_get_hobject(ctx, -1);  /* object or array */
 
21690
        DUK_ASSERT(h_target != NULL);
 
21691
        duk_push_sprintf(ctx, "%p", (void *) h_target);
 
21692
 
 
21693
        duk_dup_top(ctx);  /* -> [ ... voidp voidp ] */
 
21694
        if (duk_has_prop(ctx, js_ctx->idx_loop)) {
 
21695
                DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, "cyclic input");
 
21696
        }
 
21697
        duk_push_true(ctx);  /* -> [ ... voidp true ] */
 
21698
        duk_put_prop(ctx, js_ctx->idx_loop);  /* -> [ ... ] */
 
21699
 
 
21700
        /* c recursion check */
 
21701
 
 
21702
        DUK_ASSERT(js_ctx->recursion_depth >= 0);
 
21703
        DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 
21704
        if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
 
21705
                DUK_ERROR((duk_hthread *) ctx, DUK_ERR_RANGE_ERROR, "json encode recursion limit");
 
21706
        }
 
21707
        js_ctx->recursion_depth++;
 
21708
 
 
21709
        /* figure out indent and stepback */
 
21710
 
 
21711
        *h_indent = NULL;
 
21712
        *h_stepback = NULL;
 
21713
        if (js_ctx->h_gap != NULL) {
 
21714
                DUK_ASSERT(js_ctx->h_indent != NULL);
 
21715
 
 
21716
                *h_stepback = js_ctx->h_indent;
 
21717
                duk_push_hstring(ctx, js_ctx->h_indent);
 
21718
                duk_push_hstring(ctx, js_ctx->h_gap);
 
21719
                duk_concat(ctx, 2);
 
21720
                js_ctx->h_indent = duk_get_hstring(ctx, -1);
 
21721
                *h_indent = js_ctx->h_indent;
 
21722
                DUK_ASSERT(js_ctx->h_indent != NULL);
 
21723
 
 
21724
                /* The new indent string is left at value stack top, and will
 
21725
                 * be popped by the shared exit handler.
 
21726
                 */
 
21727
        } else {
 
21728
                DUK_ASSERT(js_ctx->h_indent == NULL);
 
21729
        }
 
21730
 
 
21731
        DUK_DDDPRINT("shared entry finished: top=%d, loop=%!T",
 
21732
                     duk_get_top(ctx), duk_get_tval(ctx, js_ctx->idx_loop));
 
21733
}
 
21734
 
 
21735
/* Shared exit handling for object/array serialization. */
 
21736
static void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_hstring **h_stepback, duk_hstring **h_indent, int *entry_top) {
 
21737
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21738
        duk_hobject *h_target;
 
21739
 
 
21740
        DUK_UNREF(h_indent);
 
21741
 
 
21742
        if (js_ctx->h_gap != NULL) {
 
21743
                DUK_ASSERT(js_ctx->h_indent != NULL);
 
21744
                DUK_ASSERT(*h_stepback != NULL);
 
21745
                DUK_ASSERT(*h_indent != NULL);
 
21746
 
 
21747
                js_ctx->h_indent = *h_stepback;  /* previous js_ctx->h_indent */
 
21748
 
 
21749
                /* Note: we don't need to pop anything because the duk_set_top()
 
21750
                 * at the end will take care of it.
 
21751
                 */
 
21752
        } else {
 
21753
                DUK_ASSERT(js_ctx->h_indent == NULL);
 
21754
                DUK_ASSERT(*h_stepback == NULL);
 
21755
                DUK_ASSERT(*h_indent == NULL);
 
21756
        }
 
21757
 
 
21758
        /* c recursion check */
 
21759
 
 
21760
        DUK_ASSERT(js_ctx->recursion_depth > 0);
 
21761
        DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
 
21762
        js_ctx->recursion_depth--;
 
21763
 
 
21764
        /* loop check */
 
21765
 
 
21766
        h_target = duk_get_hobject(ctx, *entry_top - 1);  /* original target at entry_top - 1 */
 
21767
        DUK_ASSERT(h_target != NULL);
 
21768
        duk_push_sprintf(ctx, "%p", (void *) h_target);
 
21769
 
 
21770
        duk_del_prop(ctx, js_ctx->idx_loop);  /* -> [ ... ] */
 
21771
 
 
21772
        /* restore stack top after unbalanced code paths */
 
21773
        duk_set_top(ctx, *entry_top);
 
21774
 
 
21775
        DUK_DDDPRINT("shared entry finished: top=%d, loop=%!T",
 
21776
                     duk_get_top(ctx), duk_get_tval(ctx, js_ctx->idx_loop));
 
21777
}
 
21778
 
 
21779
/* The JO(value) operation: encode object.
 
21780
 *
 
21781
 * Stack policy: [ object ] -> [ object ].
 
21782
 */
 
21783
static void duk__enc_object(duk_json_enc_ctx *js_ctx) {
 
21784
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21785
        duk_hstring *h_stepback;
 
21786
        duk_hstring *h_indent;
 
21787
        duk_hstring *h_key;
 
21788
        int entry_top;
 
21789
        int idx_obj;
 
21790
        int idx_keys;
 
21791
        int first;
 
21792
        int undef;
 
21793
        int arr_len;
 
21794
        int i;
 
21795
 
 
21796
        DUK_DDDPRINT("duk__enc_object: obj=%!T", duk_get_tval(ctx, -1));
 
21797
 
 
21798
        duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top);
 
21799
 
 
21800
        idx_obj = entry_top - 1;
 
21801
 
 
21802
        if (js_ctx->idx_proplist >= 0) {
 
21803
                idx_keys = js_ctx->idx_proplist;
 
21804
        } else {
 
21805
                /* FIXME: would be nice to enumerate an object at specified index */
 
21806
                duk_dup(ctx, idx_obj);
 
21807
                (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);  /* [ ... target ] -> [ ... target keys ] */
 
21808
                idx_keys = duk_require_normalize_index(ctx, -1);
 
21809
                /* leave stack unbalanced on purpose */
 
21810
        }
 
21811
 
 
21812
        DUK_DDDPRINT("idx_keys=%d, h_keys=%!T", idx_keys, duk_get_tval(ctx, idx_keys));
 
21813
 
 
21814
        /* Steps 8-10 have been merged to avoid a "partial" variable. */
 
21815
 
 
21816
        DUK__EMIT_1(js_ctx, '{');
 
21817
 
 
21818
        /* FIXME: keys is an internal object with all keys to be processed
 
21819
         * in its (gapless) array part.  Because nobody can touch the keys
 
21820
         * object, we could iterate its array part directly (keeping in mind
 
21821
         * that it can be reallocated).
 
21822
         */
 
21823
 
 
21824
        arr_len = duk_get_length(ctx, idx_keys);
 
21825
        first = 1;
 
21826
        for (i = 0; i < arr_len; i++) {
 
21827
                duk_get_prop_index(ctx, idx_keys, i);  /* -> [ ... key ] */
 
21828
 
 
21829
                DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
 
21830
                             duk_get_tval(ctx, idx_obj), duk_get_tval(ctx, -1));
 
21831
 
 
21832
                undef = duk__enc_value1(js_ctx, idx_obj);
 
21833
                if (undef) {
 
21834
                        /* Value would yield 'undefined', so skip key altogether.
 
21835
                         * Side effects have already happened.
 
21836
                         */
 
21837
                        continue;
 
21838
                }
 
21839
 
 
21840
                /* [ ... key val ] */
 
21841
 
 
21842
                if (first) {
 
21843
                        first = 0;
 
21844
                } else {
 
21845
                        DUK__EMIT_1(js_ctx, (char) ',');
 
21846
                }
 
21847
                if (h_indent != NULL) {
 
21848
                        DUK__EMIT_1(js_ctx, (char) 0x0a);
 
21849
                        DUK__EMIT_HSTR(js_ctx, h_indent);
 
21850
                }
 
21851
 
 
21852
                h_key = duk_get_hstring(ctx, -2);
 
21853
                DUK_ASSERT(h_key != NULL);
 
21854
                if (js_ctx->flag_avoid_key_quotes && !duk__enc_key_quotes_needed(h_key)) {
 
21855
                        /* emit key as is */
 
21856
                        DUK__EMIT_HSTR(js_ctx, h_key);
 
21857
                } else {
 
21858
                        duk__enc_quote_string(js_ctx, h_key);
 
21859
                }
 
21860
 
 
21861
                if (h_indent != NULL) {
 
21862
                        DUK__EMIT_2(js_ctx, ':', ' ');
 
21863
                } else {
 
21864
                        DUK__EMIT_1(js_ctx, ':');
 
21865
                }
 
21866
 
 
21867
                /* [ ... key val ] */
 
21868
 
 
21869
                duk__enc_value2(js_ctx);  /* -> [ ... ] */
 
21870
        }
 
21871
 
 
21872
        if (!first) {
 
21873
                if (h_stepback != NULL) {
 
21874
                        DUK_ASSERT(h_indent != NULL);
 
21875
                        DUK__EMIT_1(js_ctx, (char) 0x0a);
 
21876
                        DUK__EMIT_HSTR(js_ctx, h_stepback);
 
21877
                }
 
21878
        }
 
21879
        DUK__EMIT_1(js_ctx, '}');
 
21880
 
 
21881
        duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top);
 
21882
 
 
21883
        DUK_ASSERT_TOP(ctx, entry_top);
 
21884
}
 
21885
 
 
21886
/* The JA(value) operation: encode array.
 
21887
 *
 
21888
 * Stack policy: [ array ] -> [ array ].
 
21889
 */
 
21890
static void duk__enc_array(duk_json_enc_ctx *js_ctx) {
 
21891
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21892
        duk_hstring *h_stepback;
 
21893
        duk_hstring *h_indent;
 
21894
        int entry_top;
 
21895
        int idx_arr;
 
21896
        int undef;
 
21897
        duk_uint_t i;
 
21898
        duk_uint_t arr_len;
 
21899
 
 
21900
        DUK_DDDPRINT("duk__enc_array: array=%!T", duk_get_tval(ctx, -1));
 
21901
 
 
21902
        duk__enc_objarr_entry(js_ctx, &h_stepback, &h_indent, &entry_top);
 
21903
 
 
21904
        idx_arr = entry_top - 1;
 
21905
 
 
21906
        /* Steps 8-10 have been merged to avoid a "partial" variable. */
 
21907
 
 
21908
        DUK__EMIT_1(js_ctx, '[');
 
21909
 
 
21910
        arr_len = duk_get_length(ctx, idx_arr);
 
21911
        for (i = 0; i < arr_len; i++) {
 
21912
                DUK_DDDPRINT("array entry loop: array=%!T, h_indent=%!O, h_stepback=%!O, index=%d, arr_len=%d",
 
21913
                             duk_get_tval(ctx, idx_arr), h_indent, h_stepback, i, arr_len);
 
21914
 
 
21915
                if (i > 0) {
 
21916
                        DUK__EMIT_1(js_ctx, ',');
 
21917
                }
 
21918
                if (h_indent != NULL) {
 
21919
                        DUK__EMIT_1(js_ctx, (char) 0x0a);
 
21920
                        DUK__EMIT_HSTR(js_ctx, h_indent);
 
21921
                }
 
21922
 
 
21923
                /* FIXME: duk_push_uint_string() */
 
21924
                duk_push_number(ctx, (double) i);
 
21925
                duk_to_string(ctx, -1);  /* -> [ ... key ] */
 
21926
                undef = duk__enc_value1(js_ctx, idx_arr);
 
21927
 
 
21928
                if (undef) {
 
21929
                        DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_NULL);
 
21930
                } else {
 
21931
                        /* [ ... key val ] */
 
21932
                        duk__enc_value2(js_ctx);
 
21933
                }
 
21934
        }
 
21935
 
 
21936
        if (arr_len > 0) {
 
21937
                if (h_stepback != NULL) {
 
21938
                        DUK_ASSERT(h_indent != NULL);
 
21939
                        DUK__EMIT_1(js_ctx, (char) 0x0a);
 
21940
                        DUK__EMIT_HSTR(js_ctx, h_stepback);
 
21941
                }
 
21942
        }
 
21943
        DUK__EMIT_1(js_ctx, ']');
 
21944
 
 
21945
        duk__enc_objarr_exit(js_ctx, &h_stepback, &h_indent, &entry_top);
 
21946
 
 
21947
        DUK_ASSERT_TOP(ctx, entry_top);
 
21948
}
 
21949
 
 
21950
/* The Str(key, holder) operation: encode value, steps 1-4.
 
21951
 *
 
21952
 * Returns non-zero if the value between steps 4 and 5 would yield an
 
21953
 * 'undefined' final result.  This is useful in JO() because we need to
 
21954
 * get the side effects out, but need to know whether or not a key will
 
21955
 * be omitted from the serialization.
 
21956
 *
 
21957
 * Stack policy: [ ... key ] -> [ ... key val ]  if retval == 0.
 
21958
 *                           -> [ ... ]          if retval != 0.
 
21959
 */
 
21960
static int duk__enc_value1(duk_json_enc_ctx *js_ctx, int idx_holder) {
 
21961
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
21962
        duk_hobject *h;
 
21963
        duk_tval *tv;
 
21964
        int c;
 
21965
 
 
21966
        DUK_DDDPRINT("duk__enc_value1: idx_holder=%d, holder=%!T, key=%!T",
 
21967
                     idx_holder, duk_get_tval(ctx, idx_holder), duk_get_tval(ctx, -1));
 
21968
 
 
21969
        duk_dup_top(ctx);               /* -> [ ... key key ] */
 
21970
        duk_get_prop(ctx, idx_holder);  /* -> [ ... key val ] */
 
21971
 
 
21972
        DUK_DDDPRINT("value=%!T", duk_get_tval(ctx, -1));
 
21973
 
 
21974
        h = duk_get_hobject(ctx, -1);
 
21975
        if (h != NULL) {
 
21976
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
 
21977
                h = duk_get_hobject(ctx, -1);
 
21978
                if (h != NULL && DUK_HOBJECT_IS_CALLABLE(h)) {
 
21979
                        DUK_DDDPRINT("value is object, has callable toJSON() -> call it");
 
21980
                        duk_dup(ctx, -2);         /* -> [ ... key val toJSON val ] */
 
21981
                        duk_dup(ctx, -4);         /* -> [ ... key val toJSON val key ] */
 
21982
                        duk_call_method(ctx, 1);  /* -> [ ... key val val' ] */
 
21983
                        duk_remove(ctx, -2);      /* -> [ ... key val' ] */
 
21984
                } else {
 
21985
                        duk_pop(ctx);
 
21986
                }
 
21987
        }
 
21988
 
 
21989
        /* [ ... key val ] */
 
21990
 
 
21991
        DUK_DDDPRINT("value=%!T", duk_get_tval(ctx, -1));
 
21992
 
 
21993
        if (js_ctx->h_replacer) {
 
21994
                /* FIXME: here a "slice copy" would be useful */
 
21995
                DUK_DDDPRINT("replacer is set, call replacer");
 
21996
                duk_push_hobject(ctx, js_ctx->h_replacer);  /* -> [ ... key val replacer ] */
 
21997
                duk_dup(ctx, idx_holder);                   /* -> [ ... key val replacer holder ] */
 
21998
                duk_dup(ctx, -4);                           /* -> [ ... key val replacer holder key ] */
 
21999
                duk_dup(ctx, -4);                           /* -> [ ... key val replacer holder key val ] */
 
22000
                duk_call_method(ctx, 2);                    /* -> [ ... key val val' ] */
 
22001
                duk_remove(ctx, -2);                        /* -> [ ... key val' ] */
 
22002
        }
 
22003
 
 
22004
        /* [ ... key val ] */
 
22005
 
 
22006
        DUK_DDDPRINT("value=%!T", duk_get_tval(ctx, -1));
 
22007
 
 
22008
        tv = duk_get_tval(ctx, -1);
 
22009
        DUK_ASSERT(tv != NULL);
 
22010
        if (DUK_TVAL_IS_OBJECT(tv)) {
 
22011
                h = DUK_TVAL_GET_OBJECT(tv);
 
22012
                DUK_ASSERT(h != NULL);
 
22013
 
 
22014
                c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
 
22015
                switch (c) {
 
22016
                case DUK_HOBJECT_CLASS_NUMBER:
 
22017
                        DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()");
 
22018
                        duk_to_number(ctx, -1);
 
22019
                        break;
 
22020
                case DUK_HOBJECT_CLASS_STRING:
 
22021
                        DUK_DDDPRINT("value is a String object -> coerce with ToString()");
 
22022
                        duk_to_string(ctx, -1);
 
22023
                        break;
 
22024
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22025
                case DUK_HOBJECT_CLASS_BUFFER:
 
22026
                case DUK_HOBJECT_CLASS_POINTER:
 
22027
#endif
 
22028
                case DUK_HOBJECT_CLASS_BOOLEAN:
 
22029
                        DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value");
 
22030
                        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
22031
                        duk_remove(ctx, -2);
 
22032
                        break;
 
22033
                }
 
22034
        }
 
22035
 
 
22036
        /* [ ... key val ] */
 
22037
 
 
22038
        DUK_DDDPRINT("value=%!T", duk_get_tval(ctx, -1));
 
22039
 
 
22040
        if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
 
22041
                /* will result in undefined */
 
22042
                DUK_DDDPRINT("-> will result in undefined (type mask check)");
 
22043
                goto undef;
 
22044
        }
 
22045
 
 
22046
        /* functions are detected specially */
 
22047
        h = duk_get_hobject(ctx, -1);
 
22048
        if (h != NULL && DUK_HOBJECT_IS_CALLABLE(h)) {
 
22049
                if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
 
22050
                                     DUK_JSON_FLAG_EXT_COMPATIBLE)) {
 
22051
                        /* function will be serialized to custom format */
 
22052
                } else {
 
22053
                        /* functions are not serialized, results in undefined */
 
22054
                        DUK_DDDPRINT("-> will result in undefined (function)");
 
22055
                        goto undef;
 
22056
                }
 
22057
        }
 
22058
 
 
22059
        DUK_DDDPRINT("-> will not result in undefined");
 
22060
        return 0;
 
22061
 
 
22062
 undef:
 
22063
        duk_pop_2(ctx);
 
22064
        return 1;
 
22065
}
 
22066
 
 
22067
/* The Str(key, holder) operation: encode value, steps 5-10.
 
22068
 *
 
22069
 * This must not be called unless duk__enc_value1() returns non-zero.
 
22070
 * If so, this is guaranteed to produce a non-undefined result.
 
22071
 * Non-standard encodings (e.g. for undefined) are only used if
 
22072
 * duk__enc_value1() indicates they are accepted; they're not
 
22073
 * checked or asserted here again.
 
22074
 *
 
22075
 * Stack policy: [ ... key val ] -> [ ... ].
 
22076
 */
 
22077
static void duk__enc_value2(duk_json_enc_ctx *js_ctx) {
 
22078
        duk_context *ctx = (duk_context *) js_ctx->thr;
 
22079
        duk_tval *tv;
 
22080
 
 
22081
        DUK_DDDPRINT("duk__enc_value2: key=%!T, val=%!T",
 
22082
                     duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
22083
 
 
22084
        /* [ ... key val ] */
 
22085
 
 
22086
        tv = duk_get_tval(ctx, -1);
 
22087
        DUK_ASSERT(tv != NULL);
 
22088
 
 
22089
        switch (DUK_TVAL_GET_TAG(tv)) {
 
22090
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22091
        /* When JSONX/JSONC not in use, duk__enc_value1 will block undefined values. */
 
22092
        case DUK_TAG_UNDEFINED: {
 
22093
                DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
 
22094
                break;
 
22095
        }
 
22096
#endif
 
22097
        case DUK_TAG_NULL: {
 
22098
                DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_NULL);
 
22099
                break;
 
22100
        }
 
22101
        case DUK_TAG_BOOLEAN: {
 
22102
                DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
 
22103
                                 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
 
22104
                break;
 
22105
        }
 
22106
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22107
        /* When JSONX/JSONC not in use, duk__enc_value1 will block pointer values. */
 
22108
        case DUK_TAG_POINTER: {
 
22109
                char buf[64];  /* XXX: how to figure correct size? */
 
22110
                const char *fmt;
 
22111
                void *ptr = DUK_TVAL_GET_POINTER(tv);
 
22112
 
 
22113
                DUK_MEMZERO(buf, sizeof(buf));
 
22114
 
 
22115
                /* The #ifdef clutter here needs to handle the three cases:
 
22116
                 * (1) JSONX+JSONC, (2) JSONX only, (3) JSONC only.
 
22117
                 */
 
22118
#if defined(DUK_USE_JSONX) && defined(DUK_USE_JSONC)
 
22119
                if (js_ctx->flag_ext_custom)
 
22120
#endif
 
22121
#if defined(DUK_USE_JSONX)
 
22122
                {
 
22123
                        fmt = ptr ? "(%p)" : "(null)";
 
22124
                }
 
22125
#endif
 
22126
#if defined(DUK_USE_JSONX) && defined(DUK_USE_JSONC)
 
22127
                else
 
22128
#endif
 
22129
#if defined(DUK_USE_JSONC)
 
22130
                {
 
22131
                        fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
 
22132
                }
 
22133
#endif
 
22134
 
 
22135
                /* When ptr == NULL, the format argument is unused. */
 
22136
                DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr);  /* must not truncate */
 
22137
                DUK__EMIT_CSTR(js_ctx, buf);
 
22138
                break;
 
22139
        }
 
22140
#endif  /* DUK_USE_JSONX || DUK_USE_JSONC */
 
22141
        case DUK_TAG_STRING: {
 
22142
                duk_hstring *h = DUK_TVAL_GET_STRING(tv);
 
22143
                DUK_ASSERT(h != NULL);
 
22144
 
 
22145
                duk__enc_quote_string(js_ctx, h);
 
22146
                break;
 
22147
        }
 
22148
        case DUK_TAG_OBJECT: {
 
22149
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
22150
                DUK_ASSERT(h != NULL);
 
22151
 
 
22152
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22153
                if (DUK_HOBJECT_IS_CALLABLE(h)) {
 
22154
                        /* We only get here when doing non-standard JSON encoding */
 
22155
                        DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
 
22156
                        DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
 
22157
                } else  /* continues below */
 
22158
#endif
 
22159
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
 
22160
                        duk__enc_array(js_ctx);
 
22161
                } else {
 
22162
                        duk__enc_object(js_ctx);
 
22163
                }
 
22164
                break;
 
22165
        }
 
22166
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22167
        /* When JSONX/JSONC not in use, duk__enc_value1 will block buffer values. */
 
22168
        case DUK_TAG_BUFFER: {
 
22169
                /* Buffer values are encoded in (lowercase) hex to make the
 
22170
                 * binary data readable.  Base64 or similar would be more
 
22171
                 * compact but less readable, and the point of JSONX/JSONC
 
22172
                 * variants is to be as useful to a programmer as possible.
 
22173
                 */
 
22174
 
 
22175
                /* The #ifdef clutter here needs to handle the three cases:
 
22176
                 * (1) JSONX+JSONC, (2) JSONX only, (3) JSONC only.
 
22177
                 */
 
22178
#if defined(DUK_USE_JSONX) && defined(DUK_USE_JSONC)
 
22179
                if (js_ctx->flag_ext_custom)
 
22180
#endif
 
22181
#if defined(DUK_USE_JSONX)
 
22182
                {
 
22183
                        duk_uint8_t *p, *p_end;
 
22184
                        int x;
 
22185
                        duk_hbuffer *h;
 
22186
 
 
22187
                        h = DUK_TVAL_GET_BUFFER(tv);
 
22188
                        DUK_ASSERT(h != NULL);
 
22189
                        p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
 
22190
                        p_end = p + DUK_HBUFFER_GET_SIZE(h);
 
22191
                        DUK__EMIT_1(js_ctx, '|');
 
22192
                        while (p < p_end) {
 
22193
                                x = (int) *p++;
 
22194
                                duk_hbuffer_append_byte(js_ctx->thr, js_ctx->h_buf, duk_lc_digits[(x >> 4) & 0x0f]);
 
22195
                                duk_hbuffer_append_byte(js_ctx->thr, js_ctx->h_buf, duk_lc_digits[x & 0x0f]);
 
22196
                        }
 
22197
                        DUK__EMIT_1(js_ctx, '|');
 
22198
                }
 
22199
#endif
 
22200
#if defined(DUK_USE_JSONX) && defined(DUK_USE_JSONC)
 
22201
                else
 
22202
#endif
 
22203
#if defined(DUK_USE_JSONC)
 
22204
                {
 
22205
                        DUK_ASSERT(js_ctx->flag_ext_compatible);
 
22206
                        duk_hex_encode(ctx, -1);
 
22207
                        DUK__EMIT_CSTR(js_ctx, "{\"_buf\":");
 
22208
                        duk__enc_quote_string(js_ctx, duk_require_hstring(ctx, -1));
 
22209
                        DUK__EMIT_1(js_ctx, '}');
 
22210
                }
 
22211
#endif
 
22212
                break;
 
22213
        }
 
22214
#endif  /* DUK_USE_JSONX || DUK_USE_JSONC */
 
22215
        default: {
 
22216
                /* number */
 
22217
                double d;
 
22218
                int c;
 
22219
                int s;
 
22220
                int stridx;
 
22221
                int n2s_flags;
 
22222
                duk_hstring *h_str;
 
22223
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
22224
 
 
22225
                d = DUK_TVAL_GET_NUMBER(tv);
 
22226
                c = DUK_FPCLASSIFY(d);
 
22227
                s = DUK_SIGNBIT(d);
 
22228
                DUK_UNREF(s);
 
22229
 
 
22230
                if (!(c == DUK_FP_INFINITE || c == DUK_FP_NAN)) {
 
22231
                        DUK_ASSERT(DUK_ISFINITE(d));
 
22232
                        n2s_flags = 0;
 
22233
                        /* [ ... number ] -> [ ... string ] */
 
22234
                        duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
 
22235
                        h_str = duk_to_hstring(ctx, -1);
 
22236
                        DUK_ASSERT(h_str != NULL);
 
22237
                        DUK__EMIT_HSTR(js_ctx, h_str);
 
22238
                        break;
 
22239
                }
 
22240
 
 
22241
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22242
                if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
 
22243
                                       DUK_JSON_FLAG_EXT_COMPATIBLE))) {
 
22244
                        stridx = DUK_STRIDX_NULL;
 
22245
                } else if (c == DUK_FP_NAN) {
 
22246
                        stridx = js_ctx->stridx_custom_nan;
 
22247
                } else if (s == 0) {
 
22248
                        stridx = js_ctx->stridx_custom_posinf;
 
22249
                } else {
 
22250
                        stridx = js_ctx->stridx_custom_neginf;
 
22251
                }
 
22252
#else
 
22253
                stridx = DUK_STRIDX_NULL;
 
22254
#endif
 
22255
                DUK__EMIT_STRIDX(js_ctx, stridx);
 
22256
                break;
 
22257
        }
 
22258
        }
 
22259
 
 
22260
        /* [ ... key val ] -> [ ... ] */
 
22261
 
 
22262
        duk_pop_2(ctx);
 
22263
}
 
22264
 
 
22265
/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
 
22266
static int duk__enc_allow_into_proplist(duk_tval *tv) {
 
22267
        duk_hobject *h;
 
22268
        int c;
 
22269
 
 
22270
        DUK_ASSERT(tv != NULL);
 
22271
        if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
 
22272
                return 1;
 
22273
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
22274
                h = DUK_TVAL_GET_OBJECT(tv);
 
22275
                DUK_ASSERT(h != NULL);
 
22276
                c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
 
22277
                if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
 
22278
                        return 1;
 
22279
                }
 
22280
        }
 
22281
 
 
22282
        return 0;
 
22283
}
 
22284
 
 
22285
/*
 
22286
 *  Top level wrappers
 
22287
 */
 
22288
 
 
22289
void duk_bi_json_parse_helper(duk_context *ctx,
 
22290
                                   int idx_value,
 
22291
                                   int idx_reviver,
 
22292
                                   int flags) {
 
22293
        duk_hthread *thr = (duk_hthread *) ctx;
 
22294
        duk_json_dec_ctx js_ctx_alloc;
 
22295
        duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
 
22296
        duk_hstring *h_text;
 
22297
#ifdef DUK_USE_ASSERTIONS
 
22298
        int top_at_entry = duk_get_top(ctx);
 
22299
#endif
 
22300
 
 
22301
        DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08x, stack_top=%d",
 
22302
                     duk_get_tval(ctx, idx_value), duk_get_tval(ctx, idx_reviver),
 
22303
                     flags, duk_get_top(ctx));
 
22304
 
 
22305
        DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
 
22306
        js_ctx->thr = thr;
 
22307
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
22308
        /* nothing now */
 
22309
#endif
 
22310
        js_ctx->recursion_limit = DUK_JSON_DEC_RECURSION_LIMIT;
 
22311
 
 
22312
        /* Flag handling currently assumes that flags are consistent.  This is OK
 
22313
         * because the call sites are now strictly controlled.
 
22314
         */
 
22315
 
 
22316
        js_ctx->flags = flags;
 
22317
#ifdef DUK_USE_JSONX
 
22318
        js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
 
22319
#endif
 
22320
#ifdef DUK_USE_JSONC
 
22321
        js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
 
22322
#endif
 
22323
 
 
22324
        h_text = duk_to_hstring(ctx, idx_value);  /* coerce in-place */
 
22325
        DUK_ASSERT(h_text != NULL);
 
22326
 
 
22327
        js_ctx->p = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
 
22328
        js_ctx->p_end = ((duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
 
22329
                        DUK_HSTRING_GET_BYTELEN(h_text);
 
22330
 
 
22331
        duk__dec_value(js_ctx);  /* -> [ ... value ] */
 
22332
 
 
22333
        /* Trailing whitespace has been eaten by duk__dec_value(), so if
 
22334
         * we're not at end of input here, it's a SyntaxError.
 
22335
         */
 
22336
 
 
22337
        if (js_ctx->p != js_ctx->p_end) {
 
22338
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid json");
 
22339
        }
 
22340
 
 
22341
        if (duk_is_callable(ctx, idx_reviver)) {
 
22342
                DUK_DDDPRINT("applying reviver: %!T", duk_get_tval(ctx, idx_reviver));
 
22343
 
 
22344
                js_ctx->idx_reviver = idx_reviver;
 
22345
 
 
22346
                duk_push_object(ctx);
 
22347
                duk_dup(ctx, -2);  /* -> [ ... val root val ] */
 
22348
                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);  /* default attrs ok */
 
22349
                duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);  /* -> [ ... val root "" ] */
 
22350
 
 
22351
                DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
 
22352
                             duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
22353
 
 
22354
                duk__dec_reviver_walk(js_ctx);  /* [ ... val root "" ] -> [ ... val val' ] */
 
22355
                duk_remove(ctx, -2);            /* -> [ ... val' ] */
 
22356
        } else {
 
22357
                DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
 
22358
                             duk_get_tval(ctx, idx_reviver));
 
22359
        }
 
22360
 
 
22361
        /* Final result is at stack top. */
 
22362
 
 
22363
        DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08x, result=%!T, stack_top=%d",
 
22364
                     duk_get_tval(ctx, idx_value), duk_get_tval(ctx, idx_reviver),
 
22365
                     flags, duk_get_tval(ctx, -1), duk_get_top(ctx));
 
22366
 
 
22367
        DUK_ASSERT(duk_get_top(ctx) == top_at_entry + 1);
 
22368
}
 
22369
 
 
22370
void duk_bi_json_stringify_helper(duk_context *ctx,
 
22371
                                       int idx_value,
 
22372
                                       int idx_replacer,
 
22373
                                       int idx_space,
 
22374
                                       int flags) {
 
22375
        duk_hthread *thr = (duk_hthread *) ctx;
 
22376
        duk_json_enc_ctx js_ctx_alloc;
 
22377
        duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
 
22378
        duk_hobject *h;
 
22379
        int undef;
 
22380
        int idx_holder;
 
22381
        int top_at_entry;
 
22382
 
 
22383
        DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08x, stack_top=%d",
 
22384
                     duk_get_tval(ctx, idx_value), duk_get_tval(ctx, idx_replacer),
 
22385
                     duk_get_tval(ctx, idx_space), flags, duk_get_top(ctx));
 
22386
 
 
22387
        top_at_entry = duk_get_top(ctx);
 
22388
 
 
22389
        /*
 
22390
         *  Context init
 
22391
         */
 
22392
 
 
22393
        DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
 
22394
        js_ctx->thr = thr;
 
22395
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
22396
        js_ctx->h_replacer = NULL;
 
22397
        js_ctx->h_gap = NULL;
 
22398
        js_ctx->h_indent = NULL;
 
22399
#endif
 
22400
        js_ctx->idx_proplist = -1;
 
22401
        js_ctx->recursion_limit = DUK_JSON_ENC_RECURSION_LIMIT;
 
22402
 
 
22403
        /* Flag handling currently assumes that flags are consistent.  This is OK
 
22404
         * because the call sites are now strictly controlled.
 
22405
         */
 
22406
 
 
22407
        js_ctx->flags = flags;
 
22408
        js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
 
22409
        js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
 
22410
#ifdef DUK_USE_JSONX
 
22411
        js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
 
22412
#endif
 
22413
#ifdef DUK_USE_JSONC
 
22414
        js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
 
22415
#endif
 
22416
 
 
22417
        /* The #ifdef clutter here handles the JSONX/JSONC enable/disable
 
22418
         * combinations properly.
 
22419
         */
 
22420
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22421
#if defined(DUK_USE_JSONX)
 
22422
        if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
 
22423
                js_ctx->stridx_custom_undefined = DUK_STRIDX_UNDEFINED;
 
22424
                js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
 
22425
                js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
 
22426
                js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
 
22427
                js_ctx->stridx_custom_function =
 
22428
                        (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
 
22429
                                DUK_STRIDX_JSON_EXT_FUNCTION2 :
 
22430
                                DUK_STRIDX_JSON_EXT_FUNCTION1;
 
22431
        }
 
22432
#endif  /* DUK_USE_JSONX */
 
22433
#if defined(DUK_USE_JSONX) && defined(DUK_USE_JSONC)
 
22434
        else
 
22435
#endif  /* DUK_USE_JSONX && DUK_USE_JSONC */
 
22436
#if defined(DUK_USE_JSONC)
 
22437
        if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
 
22438
                js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
 
22439
                js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
 
22440
                js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
 
22441
                js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
 
22442
                js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
 
22443
        }
 
22444
#endif  /* DUK_USE_JSONC */
 
22445
#endif  /* DUK_USE_JSONX || DUK_USE_JSONC */
 
22446
 
 
22447
#if defined(DUK_USE_JSONX) || defined(DUK_USE_JSONC)
 
22448
        if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
 
22449
                             DUK_JSON_FLAG_EXT_COMPATIBLE)) {
 
22450
                DUK_ASSERT(js_ctx->mask_for_undefined == 0);  /* already zero */
 
22451
        }
 
22452
        else
 
22453
#endif  /* DUK_USE_JSONX || DUK_USE_JSONC */
 
22454
        {
 
22455
                js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
 
22456
                                             DUK_TYPE_MASK_POINTER |
 
22457
                                             DUK_TYPE_MASK_BUFFER;
 
22458
        }
 
22459
 
 
22460
        (void) duk_push_dynamic_buffer(ctx, 0);
 
22461
        js_ctx->h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
22462
        DUK_ASSERT(js_ctx->h_buf != NULL);
 
22463
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(js_ctx->h_buf));
 
22464
 
 
22465
        js_ctx->idx_loop = duk_push_object_internal(ctx);
 
22466
        DUK_ASSERT(js_ctx->idx_loop >= 0);
 
22467
 
 
22468
        /* [ ... buf loop ] */
 
22469
 
 
22470
        /*
 
22471
         *  Process replacer/proplist (2nd argument to JSON.stringify)
 
22472
         */
 
22473
 
 
22474
        h = duk_get_hobject(ctx, idx_replacer);
 
22475
        if (h != NULL) {
 
22476
                if (DUK_HOBJECT_IS_CALLABLE(h)) {
 
22477
                        js_ctx->h_replacer = h;
 
22478
                } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
 
22479
                        /* Here the specification requires correct array index enumeration
 
22480
                         * which is a bit tricky for sparse arrays (it is handled by the
 
22481
                         * enum setup code).  We now enumerate ancestors too, although the
 
22482
                         * specification is not very clear on whether that is required.
 
22483
                         */
 
22484
 
 
22485
                        int plist_idx = 0;
 
22486
                        int enum_flags;
 
22487
 
 
22488
                        js_ctx->idx_proplist = duk_push_array(ctx);  /* FIXME: array internal? */
 
22489
 
 
22490
                        enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
 
22491
                                     DUK_ENUM_SORT_ARRAY_INDICES;  /* expensive flag */
 
22492
                        duk_enum(ctx, idx_replacer, enum_flags);
 
22493
                        while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
 
22494
                                /* [ ... proplist enum_obj key val ] */
 
22495
                                if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
 
22496
                                        /* FIXME: duplicates should be eliminated here */
 
22497
                                        DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
22498
                                        duk_to_string(ctx, -1);  /* extra coercion of strings is OK */
 
22499
                                        duk_put_prop_index(ctx, -4, plist_idx);  /* -> [ ... proplist enum_obj key ] */
 
22500
                                        plist_idx++;
 
22501
                                        duk_pop(ctx);
 
22502
                                } else {
 
22503
                                        DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
22504
                                        duk_pop_2(ctx);
 
22505
                                }
 
22506
                        }
 
22507
                        duk_pop(ctx);  /* pop enum */
 
22508
 
 
22509
                        /* [ ... proplist ] */
 
22510
                }
 
22511
        }
 
22512
 
 
22513
        /* [ ... buf loop (proplist) ] */
 
22514
 
 
22515
        /*
 
22516
         *  Process space (3rd argument to JSON.stringify)
 
22517
         */
 
22518
 
 
22519
        h = duk_get_hobject(ctx, idx_space);
 
22520
        if (h != NULL) {
 
22521
                int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
 
22522
                if (c == DUK_HOBJECT_CLASS_NUMBER) {
 
22523
                        duk_to_number(ctx, idx_space);
 
22524
                } else if (c == DUK_HOBJECT_CLASS_STRING) {
 
22525
                        duk_to_string(ctx, idx_space);
 
22526
                }
 
22527
        }
 
22528
 
 
22529
        if (duk_is_number(ctx, idx_space)) {
 
22530
                double d;
 
22531
                int nspace;
 
22532
                char spaces[10] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };  /* FIXME:helper */
 
22533
 
 
22534
                /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
 
22535
                /* FIXME: get_clamped_int; double arithmetic is expensive */
 
22536
                (void) duk_to_int(ctx, idx_space);
 
22537
                d = duk_get_number(ctx, idx_space);
 
22538
                if (d > 10) {
 
22539
                        nspace = 10;
 
22540
                } else if (d < 1) {
 
22541
                        nspace = 0;
 
22542
                } else {
 
22543
                        nspace = (int) d;
 
22544
                }
 
22545
                DUK_ASSERT(nspace >= 0 && nspace <= 10);
 
22546
 
 
22547
                duk_push_lstring(ctx, spaces, nspace);
 
22548
                js_ctx->h_gap = duk_get_hstring(ctx, -1);
 
22549
                DUK_ASSERT(js_ctx->h_gap != NULL);
 
22550
        } else if (duk_is_string(ctx, idx_space)) {
 
22551
                /* FIXME: substring in-place at idx_place? */
 
22552
                duk_dup(ctx, idx_space);
 
22553
                duk_substring(ctx, -1, 0, 10);  /* clamp to 10 chars */
 
22554
                js_ctx->h_gap = duk_get_hstring(ctx, -1);
 
22555
                DUK_ASSERT(js_ctx->h_gap != NULL);
 
22556
        } else {
 
22557
                /* nop */
 
22558
        }
 
22559
 
 
22560
        if (js_ctx->h_gap != NULL) {
 
22561
                /* if gap is empty, behave as if not given at all */
 
22562
                if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
 
22563
                        js_ctx->h_gap = NULL;
 
22564
                } else {
 
22565
                        /* set 'indent' only if it will actually increase */
 
22566
                        js_ctx->h_indent = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
 
22567
                }
 
22568
        }
 
22569
 
 
22570
        DUK_ASSERT((js_ctx->h_gap == NULL && js_ctx->h_indent == NULL) ||
 
22571
                   (js_ctx->h_gap != NULL && js_ctx->h_indent != NULL));
 
22572
 
 
22573
        /* [ ... buf loop (proplist) (gap) ] */
 
22574
 
 
22575
        /*
 
22576
         *  Create wrapper object and serialize
 
22577
         */
 
22578
 
 
22579
        idx_holder = duk_push_object(ctx);
 
22580
        duk_dup(ctx, idx_value);
 
22581
        duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
 
22582
 
 
22583
        DUK_DDDPRINT("before: flags=0x%08x, buf=%!O, loop=%!T, replacer=%!O, proplist=%!T, gap=%!O, indent=%!O, holder=%!T",
 
22584
                     js_ctx->flags,
 
22585
                     js_ctx->h_buf,
 
22586
                     duk_get_tval(ctx, js_ctx->idx_loop),
 
22587
                     js_ctx->h_replacer,
 
22588
                     js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL,
 
22589
                     js_ctx->h_gap,
 
22590
                     js_ctx->h_indent,
 
22591
                     duk_get_tval(ctx, -1));
 
22592
        
 
22593
        /* serialize the wrapper with empty string key */
 
22594
 
 
22595
        duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
22596
 
 
22597
        /* [ ... buf loop (proplist) (gap) holder "" ] */
 
22598
 
 
22599
        undef = duk__enc_value1(js_ctx, idx_holder);  /* [ ... holder key ] -> [ ... holder key val ] */
 
22600
 
 
22601
        DUK_DDDPRINT("after: flags=0x%08x, buf=%!O, loop=%!T, replacer=%!O, proplist=%!T, gap=%!O, indent=%!O, holder=%!T",
 
22602
                     js_ctx->flags,
 
22603
                     js_ctx->h_buf,
 
22604
                     duk_get_tval(ctx, js_ctx->idx_loop),
 
22605
                     js_ctx->h_replacer,
 
22606
                     js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL,
 
22607
                     js_ctx->h_gap,
 
22608
                     js_ctx->h_indent,
 
22609
                     duk_get_tval(ctx, -3));
 
22610
 
 
22611
        if (undef) {
 
22612
                /*
 
22613
                 *  Result is undefined
 
22614
                 */
 
22615
 
 
22616
                duk_push_undefined(ctx);
 
22617
        } else {
 
22618
                /*
 
22619
                 *  Finish and convert buffer to result string
 
22620
                 */
 
22621
 
 
22622
                duk__enc_value2(js_ctx);  /* [ ... key val ] -> [ ... ] */
 
22623
                DUK_ASSERT(js_ctx->h_buf != NULL);
 
22624
                duk_push_hbuffer(ctx, (duk_hbuffer *) js_ctx->h_buf);
 
22625
                duk_to_string(ctx, -1);
 
22626
        }
 
22627
 
 
22628
        /* The stack has a variable shape here, so force it to the
 
22629
         * desired one explicitly.
 
22630
         */
 
22631
 
 
22632
        duk_replace(ctx, top_at_entry);
 
22633
        duk_set_top(ctx, top_at_entry + 1);
 
22634
 
 
22635
        DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, flags=0x%08x, result=%!T, stack_top=%d",
 
22636
                     duk_get_tval(ctx, idx_value), duk_get_tval(ctx, idx_replacer),
 
22637
                     duk_get_tval(ctx, idx_space), flags, duk_get_tval(ctx, -1), duk_get_top(ctx));
 
22638
 
 
22639
        DUK_ASSERT(duk_get_top(ctx) == top_at_entry + 1);
 
22640
}
 
22641
 
 
22642
/*
 
22643
 *  Entry points
 
22644
 */
 
22645
 
 
22646
int duk_bi_json_object_parse(duk_context *ctx) {
 
22647
        duk_bi_json_parse_helper(ctx,
 
22648
                                 0 /*idx_value*/,
 
22649
                                 1 /*idx_replacer*/,
 
22650
                                 0 /*flags*/);
 
22651
        return 1;
 
22652
}
 
22653
 
 
22654
int duk_bi_json_object_stringify(duk_context *ctx) {
 
22655
        duk_bi_json_stringify_helper(ctx,
 
22656
                                     0 /*idx_value*/,
 
22657
                                     1 /*idx_replacer*/,
 
22658
                                     2 /*idx_space*/,
 
22659
                                     0 /*flags*/);
 
22660
        return 1;
 
22661
}
 
22662
 
 
22663
#line 1 "duk_bi_logger.c"
 
22664
/*
 
22665
 *  Logging support
 
22666
 */
 
22667
 
 
22668
/* include removed: duk_internal.h */
 
22669
 
 
22670
/* 3-letter log level strings */
 
22671
static const duk_uint8_t duk__log_level_strings[] = {
 
22672
        (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
 
22673
        (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
 
22674
        (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
 
22675
        (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
 
22676
        (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
 
22677
        (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
 
22678
};
 
22679
 
 
22680
/* Constructor */
 
22681
duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
 
22682
        duk_hthread *thr = (duk_hthread *) ctx;
 
22683
        duk_int_t nargs;  /* FIXME: type */
 
22684
 
 
22685
        /* Calling as a non-constructor is not meaningful. */
 
22686
        if (!duk_is_constructor_call(ctx)) {
 
22687
                return DUK_RET_TYPE_ERROR;
 
22688
        }
 
22689
 
 
22690
        nargs = duk_get_top(ctx);
 
22691
        duk_set_top(ctx, 1);
 
22692
 
 
22693
        duk_push_this(ctx);
 
22694
 
 
22695
        /* [ name this ] */
 
22696
 
 
22697
        if (nargs == 0) {
 
22698
                /* Automatic defaulting of logger name from caller.  This would
 
22699
                 * work poorly with tail calls, but constructor calls are currently
 
22700
                 * never tail calls, so tail calls are not an issue now.
 
22701
                 */
 
22702
 
 
22703
                if (thr->callstack_top >= 2) {
 
22704
                        duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
 
22705
                        if (act_caller->func) {
 
22706
                                /* Stripping the filename might be a good idea
 
22707
                                 * ("/foo/bar/quux.js" -> logger name "quux"),
 
22708
                                 * but now used verbatim.
 
22709
                                 */
 
22710
                                duk_push_hobject(ctx, act_caller->func);
 
22711
                                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
 
22712
                                duk_replace(ctx, 0);
 
22713
                        }
 
22714
                }
 
22715
        }
 
22716
        /* the stack is unbalanced here on purpose; we only rely on the
 
22717
         * initial two values: [ name this ].
 
22718
         */
 
22719
 
 
22720
        if (duk_is_string(ctx, 0)) {
 
22721
                duk_dup(ctx, 0);
 
22722
                duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
 
22723
        } else {
 
22724
                /* don't set 'n' at all, inherited value is used as name */
 
22725
        }
 
22726
 
 
22727
        duk_compact(ctx, 1);
 
22728
 
 
22729
        return 0;  /* keep default instance */
 
22730
}
 
22731
 
 
22732
/* Default function to format objects.  Tries to use toLogString() but falls
 
22733
 * back to toString().  Any errors are propagated out without catching.
 
22734
 */
 
22735
duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
 
22736
        if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
 
22737
                /* [ arg toLogString ] */
 
22738
 
 
22739
                duk_dup(ctx, 0);
 
22740
                duk_call_method(ctx, 0);
 
22741
 
 
22742
                /* [ arg result ] */
 
22743
                return 1;
 
22744
        }
 
22745
 
 
22746
        /* [ arg undefined ] */
 
22747
        duk_pop(ctx);
 
22748
        duk_to_string(ctx, 0);
 
22749
        return 1;
 
22750
}
 
22751
 
 
22752
/* Default function to write a formatted log line.  Writes to stderr,
 
22753
 * appending a newline to the log line.
 
22754
 *
 
22755
 * The argument is a buffer whose visible size contains the log message.
 
22756
 * This function should avoid coercing the buffer to a string to avoid
 
22757
 * string table traffic.
 
22758
 */
 
22759
duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
 
22760
        const char *data;
 
22761
        duk_size_t data_len;
 
22762
 
 
22763
        DUK_UNREF(ctx);
 
22764
        DUK_UNREF(data);
 
22765
        DUK_UNREF(data_len);
 
22766
 
 
22767
#ifdef DUK_USE_FILE_IO
 
22768
        data = (const char *) duk_require_buffer(ctx, 0, &data_len);
 
22769
        DUK_FWRITE((const void *) data, 1, data_len, stderr);
 
22770
        DUK_FPUTC((int) '\n', stderr);
 
22771
        DUK_FFLUSH(stderr);
 
22772
#else
 
22773
        /* nop */
 
22774
#endif
 
22775
        return 0;
 
22776
}
 
22777
 
 
22778
/* Log frontend shared helper, magic value indicates log level.  Provides
 
22779
 * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
 
22780
 * This needs to have small footprint, reasonable performance, minimal
 
22781
 * memory churn, etc.
 
22782
 */
 
22783
duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
 
22784
        duk_hthread *thr = (duk_hthread *) ctx;
 
22785
        duk_double_t now;
 
22786
        duk_small_int_t entry_lev = duk_get_magic(ctx);
 
22787
        duk_small_int_t logger_lev;
 
22788
        duk_int_t nargs;
 
22789
        duk_int_t i;
 
22790
        duk_size_t tot_len;
 
22791
        const duk_uint8_t *arg_str;
 
22792
        duk_size_t arg_len;
 
22793
        duk_uint8_t *buf, *p;
 
22794
        const duk_uint8_t *q;
 
22795
        duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
 
22796
        duk_size_t date_len;
 
22797
        duk_small_int_t rc;
 
22798
 
 
22799
        DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
 
22800
 
 
22801
        /* XXX: sanitize to printable (and maybe ASCII) */
 
22802
        /* XXX: better multiline */
 
22803
 
 
22804
        /*
 
22805
         *  Logger arguments are:
 
22806
         *
 
22807
         *    magic: log level (0-5)
 
22808
         *    this: logger
 
22809
         *    stack: plain log args
 
22810
         *
 
22811
         *  We want to minimize memory churn so a two-pass approach
 
22812
         *  is used: first pass formats arguments and computes final
 
22813
         *  string length, second pass copies strings either into a
 
22814
         *  pre-allocated and reused buffer (short messages) or into a
 
22815
         *  newly allocated fixed buffer.  If the backend function plays
 
22816
         *  nice, it won't coerce the buffer to a string (and thus
 
22817
         *  intern it).
 
22818
         */
 
22819
 
 
22820
        nargs = duk_get_top(ctx);
 
22821
 
 
22822
        /* [ arg1 ... argN this ] */
 
22823
 
 
22824
        /*
 
22825
         *  Log level check
 
22826
         */
 
22827
 
 
22828
        duk_push_this(ctx);
 
22829
 
 
22830
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
 
22831
        logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
 
22832
        if (entry_lev < logger_lev) {
 
22833
                return 0;
 
22834
        }
 
22835
        /* log level could be popped but that's not necessary */
 
22836
 
 
22837
        now = duk_bi_date_get_now(ctx);
 
22838
        duk_bi_date_format_timeval(now, date_buf);
 
22839
        date_len = DUK_STRLEN((const char *) date_buf);
 
22840
 
 
22841
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
 
22842
        duk_to_string(ctx, -1);
 
22843
        DUK_ASSERT(duk_is_string(ctx, -1));
 
22844
 
 
22845
        /* [ arg1 ... argN this loggerLevel loggerName ] */
 
22846
 
 
22847
        /*
 
22848
         *  Pass 1
 
22849
         */
 
22850
 
 
22851
        /* Line format: <time> <entryLev> <loggerName>: <msg> */
 
22852
 
 
22853
        tot_len = 0;
 
22854
        tot_len += 3 +  /* separators: space, space, colon */
 
22855
                   3 +  /* level string */
 
22856
                   date_len +  /* time */
 
22857
                   duk_get_length(ctx, -1);  /* loggerName */
 
22858
 
 
22859
        for (i = 0; i < nargs; i++) {
 
22860
                /* When formatting an argument to a string, errors may happen from multiple
 
22861
                 * causes.  In general we want to catch obvious errors like a toLogString()
 
22862
                 * throwing an error, but we don't currently try to catch every possible
 
22863
                 * error.  In particular, internal errors (like out of memory or stack) are
 
22864
                 * not caught.  Also, we expect Error toString() to not throw an error.
 
22865
                 */
 
22866
                if (duk_is_object(ctx, i)) {
 
22867
                        /* duk_pcall_prop() may itself throw an error, but we're content
 
22868
                         * in catching the obvious errors (like toLogString() throwing an
 
22869
                         * error).
 
22870
                         */
 
22871
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT);
 
22872
                        duk_dup(ctx, i);
 
22873
                        /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
 
22874
                        /* call: this.fmt(arg) */
 
22875
                        rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
 
22876
                        if (rc) {
 
22877
                                /* Keep the error as the result (coercing it might fail below,
 
22878
                                 * but we don't catch that now).
 
22879
                                 */
 
22880
                                ;
 
22881
                        }
 
22882
                        duk_replace(ctx, i);
 
22883
                }
 
22884
                (void) duk_to_lstring(ctx, i, &arg_len);
 
22885
                tot_len++;  /* sep (even before first one) */
 
22886
                tot_len += arg_len;
 
22887
        }
 
22888
 
 
22889
        /*
 
22890
         *  Pass 2
 
22891
         */
 
22892
 
 
22893
        if (tot_len <= DUK_BI_LOGGER_SHORT_MSG_LIMIT) {
 
22894
                duk_hbuffer_dynamic *h_buf;
 
22895
 
 
22896
                DUK_DPRINT("reuse existing small log message buffer, tot_len %d", (int) tot_len);
 
22897
 
 
22898
                /* We can assert for all buffer properties because user code
 
22899
                 * never has access to heap->log_buffer.
 
22900
                 */
 
22901
 
 
22902
                DUK_ASSERT(thr != NULL);
 
22903
                DUK_ASSERT(thr->heap != NULL);
 
22904
                h_buf = thr->heap->log_buffer;
 
22905
                DUK_ASSERT(h_buf != NULL);
 
22906
                DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_buf));
 
22907
                DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_USABLE_SIZE(h_buf) == DUK_BI_LOGGER_SHORT_MSG_LIMIT);
 
22908
 
 
22909
                /* Set buffer 'visible size' to actual message length and
 
22910
                 * push it to the stack.
 
22911
                 */
 
22912
 
 
22913
                DUK_HBUFFER_SET_SIZE((duk_hbuffer *) h_buf, tot_len);
 
22914
                duk_push_hbuffer(ctx, (duk_hbuffer *) h_buf);
 
22915
                buf = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h_buf);
 
22916
        } else {
 
22917
                DUK_DPRINT("use a one-off large log message buffer, tot_len %d", (int) tot_len);
 
22918
                buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
 
22919
        }
 
22920
        DUK_ASSERT(buf != NULL);
 
22921
        p = buf;
 
22922
 
 
22923
        DUK_MEMCPY((void *) p, (void *) date_buf, date_len);
 
22924
        p += date_len;
 
22925
        *p++ = (duk_uint8_t) DUK_ASC_SPACE;
 
22926
 
 
22927
        q = duk__log_level_strings + (entry_lev * 3);
 
22928
        DUK_MEMCPY((void *) p, (void *) q, (duk_size_t) 3);
 
22929
        p += 3;
 
22930
 
 
22931
        *p++ = (duk_uint8_t) DUK_ASC_SPACE;
 
22932
 
 
22933
        arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
 
22934
        DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len);
 
22935
        p += arg_len;
 
22936
 
 
22937
        *p++ = (duk_uint8_t) DUK_ASC_COLON;
 
22938
 
 
22939
        for (i = 0; i < nargs; i++) {
 
22940
                *p++ = (duk_uint8_t) DUK_ASC_SPACE;
 
22941
 
 
22942
                arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
 
22943
                DUK_ASSERT(arg_str != NULL);
 
22944
                DUK_MEMCPY((void *) p, (const void *) arg_str, arg_len);
 
22945
                p += arg_len;
 
22946
        }
 
22947
        DUK_ASSERT(buf + tot_len == p);
 
22948
 
 
22949
        /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
 
22950
 
 
22951
        /* Call this.raw(msg); look up through the instance allows user to override
 
22952
         * the raw() function in the instance or in the prototype for maximum
 
22953
         * flexibility.
 
22954
         */
 
22955
        duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW);
 
22956
        duk_dup(ctx, -2);
 
22957
        /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
 
22958
        duk_call_prop(ctx, -6, 1);  /* this.raw(buffer) */
 
22959
 
 
22960
        return 0;
 
22961
}
 
22962
#line 1 "duk_bi_math.c"
 
22963
/*
 
22964
 *  Math built-ins
 
22965
 */
 
22966
 
 
22967
/* include removed: duk_internal.h */
 
22968
 
 
22969
/*
 
22970
 *  Use static helpers which can work with math.h functions matching
 
22971
 *  the following signatures. This is not portable if any of these math
 
22972
 *  functions is actually a macro.
 
22973
 *
 
22974
 *  Typing here is intentionally 'double' because that's what the standard
 
22975
 *  library APIs use.
 
22976
 */
 
22977
 
 
22978
typedef double (*duk__one_arg_func)(double);
 
22979
typedef double (*duk__two_arg_func)(double, double);
 
22980
 
 
22981
static int duk__math_minmax(duk_context *ctx, double initial, duk__two_arg_func min_max) {
 
22982
        duk_int_t n = duk_get_top(ctx);
 
22983
        duk_int_t i;
 
22984
        double res = initial;
 
22985
        double t;
 
22986
 
 
22987
        /*
 
22988
         *  Note: fmax() does not match the E5 semantics.  E5 requires
 
22989
         *  that if -any- input to Math.max() is a NaN, the result is a
 
22990
         *  NaN.  fmax() will return a NaN only if -both- inputs are NaN.
 
22991
         *  Same applies to fmin().
 
22992
         *
 
22993
         *  Note: every input value must be coerced with ToNumber(), even
 
22994
         *  if we know the result will be a NaN anyway: ToNumber() may have
 
22995
         *  side effects for which even order of evaluation matters.
 
22996
         */
 
22997
 
 
22998
        for (i = 0; i < n; i++) {
 
22999
                t = duk_to_number(ctx, i);
 
23000
                if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
 
23001
                        /* Note: not normalized, but duk_push_number() will normalize */
 
23002
                        res = DUK_DOUBLE_NAN;
 
23003
                } else {
 
23004
                        res = min_max(res, t);
 
23005
                }
 
23006
        }
 
23007
 
 
23008
        duk_push_number(ctx, res);
 
23009
        return 1;
 
23010
}
 
23011
 
 
23012
static double duk__fmin_fixed(double x, double y) {
 
23013
        /* fmin() with args -0 and +0 is not guaranteed to return
 
23014
         * -0 as Ecmascript requires.
 
23015
         */
 
23016
        if (x == 0 && y == 0) {
 
23017
                /* XXX: what's the safest way of creating a negative zero? */
 
23018
                if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) {
 
23019
                        return -0.0;
 
23020
                } else {
 
23021
                        return +0.0;
 
23022
                }
 
23023
        }
 
23024
#ifdef DUK_USE_MATH_FMIN
 
23025
        return DUK_FMIN(x, y);
 
23026
#else
 
23027
        return (x < y ? x : y);
 
23028
#endif
 
23029
}
 
23030
 
 
23031
static double duk__fmax_fixed(double x, double y) {
 
23032
        /* fmax() with args -0 and +0 is not guaranteed to return
 
23033
         * +0 as Ecmascript requires.
 
23034
         */
 
23035
        if (x == 0 && y == 0) {
 
23036
                if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
 
23037
                        return +0.0;
 
23038
                } else {
 
23039
                        return -0.0;
 
23040
                }
 
23041
        }
 
23042
#ifdef DUK_USE_MATH_FMAX
 
23043
        return DUK_FMAX(x, y);
 
23044
#else
 
23045
        return (x > y ? x : y);
 
23046
#endif
 
23047
}
 
23048
 
 
23049
static double duk__round_fixed(double x) {
 
23050
        /* Numbers half-way between integers must be rounded towards +Infinity,
 
23051
         * e.g. -3.5 must be rounded to -3 (not -4).  When rounded to zero, zero
 
23052
         * sign must be set appropriately.  E5.1 Section 15.8.2.15.
 
23053
         *
 
23054
         * Note that ANSI C round() is "round to nearest integer, away from zero",
 
23055
         * which is incorrect for negative values.  Here we make do with floor().
 
23056
         */
 
23057
 
 
23058
        int c = DUK_FPCLASSIFY(x);
 
23059
        if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
 
23060
                return x;
 
23061
        }
 
23062
 
 
23063
        /*
 
23064
         *  x is finite and non-zero
 
23065
         *
 
23066
         *  -1.6 -> floor(-1.1) -> -2
 
23067
         *  -1.5 -> floor(-1.0) -> -1  (towards +Inf)
 
23068
         *  -1.4 -> floor(-0.9) -> -1
 
23069
         *  -0.5 -> -0.0               (special case)
 
23070
         *  -0.1 -> -0.0               (special case)
 
23071
         *  +0.1 -> +0.0               (special case)
 
23072
         *  +0.5 -> floor(+1.0) -> 1   (towards +Inf)
 
23073
         *  +1.4 -> floor(+1.9) -> 1
 
23074
         *  +1.5 -> floor(+2.0) -> 2   (towards +Inf)
 
23075
         *  +1.6 -> floor(+2.1) -> 2
 
23076
         */
 
23077
 
 
23078
        if (x >= -0.5 && x < 0.5) {
 
23079
                /* +0.5 is handled by floor, this is on purpose */
 
23080
                if (x < 0.0) {
 
23081
                        return -0.0;
 
23082
                } else {
 
23083
                        return +0.0;
 
23084
                }
 
23085
        }
 
23086
 
 
23087
        return DUK_FLOOR(x + 0.5);
 
23088
}
 
23089
 
 
23090
static double duk__pow_fixed(double x, double y) {
 
23091
        /* The ANSI C pow() semantics differ from Ecmascript.
 
23092
         *
 
23093
         * E.g. when x==1 and y is +/- infinite, the Ecmascript required
 
23094
         * result is NaN, while at least Linux pow() returns 1.
 
23095
         */
 
23096
 
 
23097
        int cx, cy, sx;
 
23098
 
 
23099
        DUK_UNREF(cx);
 
23100
        DUK_UNREF(sx);
 
23101
        cy = DUK_FPCLASSIFY(y);
 
23102
 
 
23103
        if (cy == DUK_FP_NAN) {
 
23104
                goto ret_nan;
 
23105
        }
 
23106
        if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
 
23107
                goto ret_nan;
 
23108
        }
 
23109
#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
 
23110
        /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
 
23111
         * correctly handle some cases where x=+/-0.  Specific fixes to these
 
23112
         * here.
 
23113
         */
 
23114
        cx = DUK_FPCLASSIFY(x);
 
23115
        if (cx == DUK_FP_ZERO && y < 0.0) {
 
23116
                sx = DUK_SIGNBIT(x);
 
23117
                if (sx == 0) {
 
23118
                        /* Math.pow(+0,y) should be Infinity when y<0.  NetBSD pow()
 
23119
                         * returns -Infinity instead when y is <0 and finite.  The
 
23120
                         * if-clause also catches y == -Infinity (which works even
 
23121
                         * without the fix).
 
23122
                         */
 
23123
                        return DUK_DOUBLE_INFINITY;
 
23124
                } else {
 
23125
                        /* Math.pow(-0,y) where y<0 should be:
 
23126
                         *   - -Infinity if y<0 and an odd integer
 
23127
                         *   - Infinity otherwise
 
23128
                         * NetBSD pow() returns -Infinity for all finite y<0.  The
 
23129
                         * if-clause also catches y == -Infinity (which works even
 
23130
                         * without the fix).
 
23131
                         */
 
23132
 
 
23133
                        /* fmod() return value has same sign as input (negative) so
 
23134
                         * the result here will be in the range ]-2,0], 1 indicates
 
23135
                         * odd.  If x is -Infinity, NaN is returned and the odd check
 
23136
                         * always concludes "not odd" which results in desired outcome.
 
23137
                         */
 
23138
                        double tmp = DUK_FMOD(y, 2);
 
23139
                        if (tmp == -1.0) {
 
23140
                                return -DUK_DOUBLE_INFINITY;
 
23141
                        } else {
 
23142
                                /* Not odd, or y == -Infinity */
 
23143
                                return DUK_DOUBLE_INFINITY;
 
23144
                        }
 
23145
                }
 
23146
        }
 
23147
#endif
 
23148
        return DUK_POW(x, y);
 
23149
 
 
23150
 ret_nan:
 
23151
        return DUK_DOUBLE_NAN;
 
23152
}
 
23153
 
 
23154
/* order must match constants in genbuiltins.py */
 
23155
static const duk__one_arg_func duk__one_arg_funcs[] = {
 
23156
        DUK_FABS,
 
23157
        DUK_ACOS,
 
23158
        DUK_ASIN,
 
23159
        DUK_ATAN,
 
23160
        DUK_CEIL,
 
23161
        DUK_COS,
 
23162
        DUK_EXP,
 
23163
        DUK_FLOOR,
 
23164
        DUK_LOG,
 
23165
        duk__round_fixed,
 
23166
        DUK_SIN,
 
23167
        DUK_SQRT,
 
23168
        DUK_TAN
 
23169
};
 
23170
 
 
23171
/* order must match constants in genbuiltins.py */
 
23172
static const duk__two_arg_func duk__two_arg_funcs[] = {
 
23173
        DUK_ATAN2,
 
23174
        duk__pow_fixed
 
23175
};
 
23176
 
 
23177
duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
 
23178
        duk_small_int_t fun_idx = duk_get_magic(ctx);
 
23179
        duk__one_arg_func fun;
 
23180
 
 
23181
        DUK_ASSERT(fun_idx >= 0);
 
23182
        DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
 
23183
        fun = duk__one_arg_funcs[fun_idx];
 
23184
        /* FIXME: double typing here: double or duk_double_t? */
 
23185
        duk_push_number(ctx, fun((double) duk_to_number(ctx, 0)));
 
23186
        return 1;
 
23187
}
 
23188
 
 
23189
duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
 
23190
        duk_small_int_t fun_idx = duk_get_magic(ctx);
 
23191
        duk__two_arg_func fun;
 
23192
 
 
23193
        DUK_ASSERT(fun_idx >= 0);
 
23194
        DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
 
23195
        fun = duk__two_arg_funcs[fun_idx];
 
23196
        /* FIXME: double typing here: double or duk_double_t? */
 
23197
        duk_push_number(ctx, fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1)));
 
23198
        return 1;
 
23199
}
 
23200
 
 
23201
duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
 
23202
        return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
 
23203
}
 
23204
 
 
23205
duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
 
23206
        return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
 
23207
}
 
23208
 
 
23209
duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
 
23210
        duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx));
 
23211
        return 1;
 
23212
}
 
23213
#line 1 "duk_bi_number.c"
 
23214
/*
 
23215
 *  Number built-ins
 
23216
 */
 
23217
 
 
23218
/* FIXME: needs to be refactored when exact parsing / string conversion
 
23219
 * primitives are implemented.
 
23220
 */
 
23221
 
 
23222
/* include removed: duk_internal.h */
 
23223
 
 
23224
static double duk__push_this_number_plain(duk_context *ctx) {
 
23225
        duk_hobject *h;
 
23226
 
 
23227
        /* Number built-in accepts a plain number or a Number object (whose
 
23228
         * internal value is operated on).  Other types cause TypeError.
 
23229
         */
 
23230
 
 
23231
        duk_push_this(ctx);
 
23232
        if (duk_is_number(ctx, -1)) {
 
23233
                DUK_DDDPRINT("plain number value: %!T", duk_get_tval(ctx, -1));
 
23234
                goto done;
 
23235
        }
 
23236
        h = duk_get_hobject(ctx, -1);
 
23237
        if (!h || 
 
23238
            (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
 
23239
                DUK_DDDPRINT("unacceptable this value: %!T", duk_get_tval(ctx, -1));
 
23240
                DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, "expected a number");
 
23241
        }
 
23242
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
23243
        DUK_ASSERT(duk_is_number(ctx, -1));
 
23244
        DUK_DDDPRINT("number object: %!T, internal value: %!T", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
23245
        duk_remove(ctx, -2);
 
23246
 
 
23247
 done:
 
23248
        return duk_get_number(ctx, -1);
 
23249
}
 
23250
 
 
23251
int duk_bi_number_constructor(duk_context *ctx) {
 
23252
        int nargs;
 
23253
        duk_hobject *h_this;
 
23254
 
 
23255
        /*
 
23256
         *  The Number constructor uses ToNumber(arg) for number coercion
 
23257
         *  (coercing an undefined argument to NaN).  However, if the
 
23258
         *  argument is not given at all, +0 must be used instead.  To do
 
23259
         *  this, a vararg function is used.
 
23260
         */
 
23261
 
 
23262
        nargs = duk_get_top(ctx);
 
23263
        if (nargs == 0) {
 
23264
                duk_push_int(ctx, 0);
 
23265
        }
 
23266
        duk_to_number(ctx, 0);
 
23267
        duk_set_top(ctx, 1);
 
23268
        DUK_ASSERT_TOP(ctx, 1);
 
23269
 
 
23270
        if (!duk_is_constructor_call(ctx)) {
 
23271
                return 1;
 
23272
        }
 
23273
 
 
23274
        /*
 
23275
         *  E5 Section 15.7.2.1 requires that the constructed object
 
23276
         *  must have the original Number.prototype as its internal
 
23277
         *  prototype.  However, since Number.prototype is non-writable
 
23278
         *  and non-configurable, this doesn't have to be enforced here:
 
23279
         *  The default object (bound to 'this') is OK, though we have
 
23280
         *  to change its class.
 
23281
         *
 
23282
         *  Internal value set to ToNumber(arg) or +0; if no arg given,
 
23283
         *  ToNumber(undefined) = NaN, so special treatment is needed
 
23284
         *  (above).  String internal value is immutable.
 
23285
         */
 
23286
 
 
23287
        /* FIXME: helper */
 
23288
        duk_push_this(ctx);
 
23289
        h_this = duk_get_hobject(ctx, -1);
 
23290
        DUK_ASSERT(h_this != NULL);
 
23291
        DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
 
23292
 
 
23293
        DUK_ASSERT(h_this->prototype == ((duk_hthread *) ctx)->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
 
23294
        DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
 
23295
        DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
 
23296
 
 
23297
        duk_dup(ctx, 0);  /* -> [ val obj val ] */
 
23298
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
 
23299
        return 0;  /* no return value -> don't replace created value */
 
23300
}
 
23301
 
 
23302
int duk_bi_number_prototype_value_of(duk_context *ctx) {
 
23303
        (void) duk__push_this_number_plain(ctx);
 
23304
        return 1;
 
23305
}
 
23306
 
 
23307
int duk_bi_number_prototype_to_string(duk_context *ctx) {
 
23308
        int radix;
 
23309
        int n2s_flags;
 
23310
 
 
23311
        (void) duk__push_this_number_plain(ctx);
 
23312
        if (duk_is_undefined(ctx, 0)) {
 
23313
                radix = 10;
 
23314
        } else {
 
23315
                radix = duk_to_int_check_range(ctx, 0, 2, 36);
 
23316
        }
 
23317
        DUK_DDDPRINT("radix=%d", radix);
 
23318
 
 
23319
        n2s_flags = 0;
 
23320
 
 
23321
        duk_numconv_stringify(ctx,
 
23322
                              radix /*radix*/,
 
23323
                              0 /*digits*/,
 
23324
                              n2s_flags /*flags*/);
 
23325
        return 1;
 
23326
}
 
23327
 
 
23328
int duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
 
23329
        /* FIXME: just use toString() for now; permitted although not recommended.
 
23330
         * nargs==1, so radix is passed to toString().
 
23331
         */
 
23332
        return duk_bi_number_prototype_to_string(ctx);
 
23333
}
 
23334
 
 
23335
/*
 
23336
 *  toFixed(), toExponential(), toPrecision()
 
23337
 */
 
23338
 
 
23339
/* FIXME: shared helper for toFixed(), toExponential(), toPrecision()? */
 
23340
 
 
23341
int duk_bi_number_prototype_to_fixed(duk_context *ctx) {
 
23342
        int frac_digits;
 
23343
        double d;
 
23344
        int c;
 
23345
        int n2s_flags;
 
23346
 
 
23347
        frac_digits = duk_to_int_check_range(ctx, 0, 0, 20);
 
23348
        d = duk__push_this_number_plain(ctx);
 
23349
 
 
23350
        c = DUK_FPCLASSIFY(d);
 
23351
        if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
 
23352
                goto use_to_string;
 
23353
        }
 
23354
 
 
23355
        if (d >= 1.0e21 || d <= -1.0e21) {
 
23356
                goto use_to_string;
 
23357
        }
 
23358
 
 
23359
        n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
 
23360
                    DUK_N2S_FLAG_FRACTION_DIGITS;
 
23361
 
 
23362
        duk_numconv_stringify(ctx,
 
23363
                              10 /*radix*/,
 
23364
                              frac_digits /*digits*/,
 
23365
                              n2s_flags /*flags*/);
 
23366
        return 1;
 
23367
 
 
23368
 use_to_string:
 
23369
        DUK_ASSERT_TOP(ctx, 2);
 
23370
        duk_to_string(ctx, -1);
 
23371
        return 1;
 
23372
}
 
23373
 
 
23374
int duk_bi_number_prototype_to_exponential(duk_context *ctx) {
 
23375
        int frac_undefined;
 
23376
        int frac_digits;
 
23377
        double d;
 
23378
        int c;
 
23379
        int n2s_flags;
 
23380
 
 
23381
        d = duk__push_this_number_plain(ctx);
 
23382
 
 
23383
        frac_undefined = duk_is_undefined(ctx, 0);
 
23384
        duk_to_int(ctx, 0);  /* for side effects */
 
23385
 
 
23386
        c = DUK_FPCLASSIFY(d);
 
23387
        if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
 
23388
                goto use_to_string;
 
23389
        }
 
23390
 
 
23391
        frac_digits = duk_to_int_check_range(ctx, 0, 0, 20);
 
23392
 
 
23393
        n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
 
23394
                   (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
 
23395
 
 
23396
        duk_numconv_stringify(ctx,
 
23397
                              10 /*radix*/,
 
23398
                              frac_digits + 1 /*leading digit + fractions*/,
 
23399
                              n2s_flags /*flags*/);
 
23400
        return 1;
 
23401
 
 
23402
 use_to_string:
 
23403
        DUK_ASSERT_TOP(ctx, 2);
 
23404
        duk_to_string(ctx, -1);
 
23405
        return 1;
 
23406
}
 
23407
 
 
23408
int duk_bi_number_prototype_to_precision(duk_context *ctx) {
 
23409
        /* The specification has quite awkward order of coercion and
 
23410
         * checks for toPrecision().  The operations below are a bit
 
23411
         * reordered, within constraints of observable side effects.
 
23412
         */
 
23413
 
 
23414
        double d;
 
23415
        int prec;
 
23416
        int c;
 
23417
        int n2s_flags;
 
23418
 
 
23419
        DUK_ASSERT_TOP(ctx, 1);
 
23420
 
 
23421
        d = duk__push_this_number_plain(ctx);
 
23422
        if (duk_is_undefined(ctx, 0)) {
 
23423
                goto use_to_string;
 
23424
        }
 
23425
        DUK_ASSERT_TOP(ctx, 2);
 
23426
 
 
23427
        duk_to_int(ctx, 0);  /* for side effects */
 
23428
 
 
23429
        c = DUK_FPCLASSIFY(d);
 
23430
        if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
 
23431
                goto use_to_string;
 
23432
        }
 
23433
 
 
23434
        prec = duk_to_int_check_range(ctx, 0, 1, 21);
 
23435
 
 
23436
        n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
 
23437
                    DUK_N2S_FLAG_NO_ZERO_PAD;
 
23438
 
 
23439
        duk_numconv_stringify(ctx,
 
23440
                              10 /*radix*/,
 
23441
                              prec /*digits*/,
 
23442
                              n2s_flags /*flags*/);
 
23443
        return 1;
 
23444
 
 
23445
 use_to_string:
 
23446
        /* Used when precision is undefined; also used for NaN (-> "NaN"),
 
23447
         * and +/- infinity (-> "Infinity", "-Infinity").
 
23448
         */
 
23449
 
 
23450
        DUK_ASSERT_TOP(ctx, 2);
 
23451
        duk_to_string(ctx, -1);
 
23452
        return 1;
 
23453
}
 
23454
 
 
23455
#line 1 "duk_bi_object.c"
 
23456
/*
 
23457
 *  Object built-ins
 
23458
 */
 
23459
 
 
23460
/* include removed: duk_internal.h */
 
23461
 
 
23462
duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
 
23463
        if (!duk_is_constructor_call(ctx) &&
 
23464
            !duk_is_null_or_undefined(ctx, 0)) {
 
23465
                duk_to_object(ctx, 0);
 
23466
                return 1;
 
23467
        }
 
23468
 
 
23469
        if (duk_is_object(ctx, 0)) {
 
23470
                return 1;
 
23471
        }
 
23472
 
 
23473
        /* Pointer and buffer primitive values are treated like other
 
23474
         * primitives values which have a fully fledged object counterpart:
 
23475
         * promote to an object value.
 
23476
         */
 
23477
        if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
 
23478
                                        DUK_TYPE_MASK_BOOLEAN |
 
23479
                                        DUK_TYPE_MASK_NUMBER |
 
23480
                                        DUK_TYPE_MASK_POINTER |
 
23481
                                        DUK_TYPE_MASK_BUFFER)) {
 
23482
                duk_to_object(ctx, 0);
 
23483
                return 1;
 
23484
        }
 
23485
 
 
23486
        duk_push_object_helper(ctx,
 
23487
                               DUK_HOBJECT_FLAG_EXTENSIBLE |
 
23488
                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
23489
                               DUK_BIDX_OBJECT_PROTOTYPE);
 
23490
        return 1;
 
23491
}
 
23492
 
 
23493
duk_ret_t duk_bi_object_constructor_get_prototype_of(duk_context *ctx) {
 
23494
        duk_hobject *h;
 
23495
 
 
23496
        h = duk_require_hobject(ctx, 0);
 
23497
        DUK_ASSERT(h != NULL);
 
23498
 
 
23499
        /* XXX: should the API call handle this directly, i.e. attempt
 
23500
         * to duk_push_hobject(ctx, null) would push a null instead?
 
23501
         * (On the other hand 'undefined' would be just as logical, but
 
23502
         * not wanted here.)
 
23503
         */
 
23504
 
 
23505
        if (h->prototype) {
 
23506
                duk_push_hobject(ctx, h->prototype);
 
23507
        } else {
 
23508
                duk_push_null(ctx);
 
23509
        }
 
23510
        return 1;
 
23511
}
 
23512
 
 
23513
duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
 
23514
        /* FIXME: no need for indirect call */
 
23515
        return duk_hobject_object_get_own_property_descriptor(ctx);
 
23516
}
 
23517
 
 
23518
duk_ret_t duk_bi_object_constructor_get_own_property_names(duk_context *ctx) {
 
23519
        DUK_ASSERT_TOP(ctx, 1);
 
23520
        (void) duk_require_hobject(ctx, 0);
 
23521
        return duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_INCLUDE_NONENUMERABLE |
 
23522
                                                    DUK_ENUM_OWN_PROPERTIES_ONLY);
 
23523
}
 
23524
 
 
23525
duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
 
23526
        duk_tval *tv;
 
23527
        duk_hobject *proto = NULL;
 
23528
 
 
23529
        DUK_ASSERT_TOP(ctx, 2);
 
23530
 
 
23531
        tv = duk_get_tval(ctx, 0);
 
23532
        DUK_ASSERT(tv != NULL);
 
23533
        if (DUK_TVAL_IS_NULL(tv)) {
 
23534
                ;
 
23535
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
23536
                proto = DUK_TVAL_GET_OBJECT(tv);
 
23537
                DUK_ASSERT(proto != NULL);
 
23538
        } else {
 
23539
                return DUK_RET_TYPE_ERROR;
 
23540
        }
 
23541
 
 
23542
        (void) duk_push_object_helper_proto(ctx,
 
23543
                                            DUK_HOBJECT_FLAG_EXTENSIBLE |
 
23544
                                            DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
23545
                                            proto);
 
23546
 
 
23547
        if (!duk_is_undefined(ctx, 1)) {
 
23548
                /* [ O Properties obj ] */
 
23549
 
 
23550
                /* Use original function.  No need to get it explicitly,
 
23551
                 * just call the helper.
 
23552
                 */
 
23553
 
 
23554
                duk_replace(ctx, 0);
 
23555
 
 
23556
                /* [ obj Properties ] */
 
23557
 
 
23558
                return duk_hobject_object_define_properties(ctx);
 
23559
        }
 
23560
 
 
23561
        /* [ O Properties obj ] */
 
23562
 
 
23563
        return 1;
 
23564
}
 
23565
 
 
23566
duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
 
23567
        /* FIXME: no need for indirect call */
 
23568
        return duk_hobject_object_define_property(ctx);
 
23569
}
 
23570
 
 
23571
duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
 
23572
        /* FIXME: no need for indirect call */
 
23573
        return duk_hobject_object_define_properties(ctx);
 
23574
}
 
23575
 
 
23576
duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
 
23577
        duk_hthread *thr = (duk_hthread *) ctx;
 
23578
        duk_hobject *h;
 
23579
        int is_freeze;
 
23580
 
 
23581
        h = duk_require_hobject(ctx, 0);
 
23582
        DUK_ASSERT(h != NULL);
 
23583
 
 
23584
        is_freeze = duk_get_magic(ctx);
 
23585
        duk_hobject_object_seal_freeze_helper(thr, h, is_freeze /*freeze*/);
 
23586
 
 
23587
        /* Sealed and frozen objects cannot gain any more properties,
 
23588
         * so this is a good time to compact them.
 
23589
         */
 
23590
        duk_hobject_compact_props(thr, h);
 
23591
 
 
23592
        return 1;
 
23593
}
 
23594
 
 
23595
duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
 
23596
        duk_hthread *thr = (duk_hthread *) ctx;
 
23597
        duk_hobject *h;
 
23598
 
 
23599
        h = duk_require_hobject(ctx, 0);
 
23600
        DUK_ASSERT(h != NULL);
 
23601
 
 
23602
        DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
 
23603
 
 
23604
        /* A non-extensible object cannot gain any more properties,
 
23605
         * so this is a good time to compact.
 
23606
         */
 
23607
        duk_hobject_compact_props(thr, h);
 
23608
        
 
23609
        return 1;
 
23610
}
 
23611
 
 
23612
duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
 
23613
        duk_hobject *h;
 
23614
        int is_frozen;
 
23615
        int rc;
 
23616
 
 
23617
        h = duk_require_hobject(ctx, 0);
 
23618
        DUK_ASSERT(h != NULL);
 
23619
 
 
23620
        is_frozen = duk_get_magic(ctx);
 
23621
        rc = duk_hobject_object_is_sealed_frozen_helper(h, is_frozen /*is_frozen*/);
 
23622
        duk_push_boolean(ctx ,rc);
 
23623
        return 1;
 
23624
}
 
23625
 
 
23626
duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
 
23627
        duk_hobject *h;
 
23628
 
 
23629
        h = duk_require_hobject(ctx, 0);
 
23630
        DUK_ASSERT(h != NULL);
 
23631
 
 
23632
        duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
 
23633
        return 1;
 
23634
}
 
23635
 
 
23636
duk_ret_t duk_bi_object_constructor_keys(duk_context *ctx) {
 
23637
        DUK_ASSERT_TOP(ctx, 1);
 
23638
        (void) duk_require_hobject(ctx, 0);
 
23639
        return duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY);
 
23640
}
 
23641
 
 
23642
duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
 
23643
        duk_hthread *thr = (duk_hthread *) ctx;
 
23644
 
 
23645
        duk_push_this(ctx);
 
23646
        duk_push_string(ctx, "[object ");
 
23647
 
 
23648
        if (duk_is_undefined(ctx, -2)) {
 
23649
                duk_push_string(ctx, "Undefined");
 
23650
        } else if (duk_is_null(ctx, -2)) {
 
23651
                duk_push_string(ctx, "Null");
 
23652
        } else {
 
23653
                duk_hobject *h_this;
 
23654
                duk_hstring *h_classname;
 
23655
 
 
23656
                duk_to_object(ctx, -2);
 
23657
                h_this = duk_get_hobject(ctx, -2);
 
23658
                DUK_ASSERT(h_this != NULL);
 
23659
 
 
23660
                h_classname = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_this);
 
23661
                DUK_ASSERT(h_classname != NULL);
 
23662
 
 
23663
                duk_push_hstring(ctx, h_classname);
 
23664
        }
 
23665
 
 
23666
        duk_push_string(ctx, "]");
 
23667
        duk_concat(ctx, 3);
 
23668
        return 1;
 
23669
}
 
23670
 
 
23671
duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
 
23672
        DUK_ASSERT_TOP(ctx, 0);
 
23673
        (void) duk_push_this_coercible_to_object(ctx);
 
23674
        duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
 
23675
        if (!duk_is_callable(ctx, 1)) {
 
23676
                return DUK_RET_TYPE_ERROR;
 
23677
        }
 
23678
        duk_dup(ctx, 0);  /* -> [ O toString O ] */
 
23679
        duk_call_method(ctx, 0);  /* FIXME: call method tailcall? */
 
23680
        return 1;
 
23681
}
 
23682
 
 
23683
duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
 
23684
        (void) duk_push_this_coercible_to_object(ctx);
 
23685
        return 1;
 
23686
}
 
23687
 
 
23688
duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
 
23689
        duk_hthread *thr = (duk_hthread *) ctx;
 
23690
        duk_hobject *h_v;
 
23691
        duk_hobject *h_obj;
 
23692
 
 
23693
        DUK_ASSERT_TOP(ctx, 1);
 
23694
 
 
23695
        h_v = duk_get_hobject(ctx, 0);
 
23696
        if (!h_v) {
 
23697
                duk_push_false(ctx);  /* FIXME: tail call: return duk_push_false(ctx) */
 
23698
                return 1;
 
23699
        }
 
23700
 
 
23701
        h_obj = duk_push_this_coercible_to_object(ctx);
 
23702
        DUK_ASSERT(h_obj != NULL);
 
23703
 
 
23704
        /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare */
 
23705
        duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, h_v->prototype, h_obj));
 
23706
        return 1;
 
23707
}
 
23708
 
 
23709
duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
 
23710
        return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
 
23711
}
 
23712
 
 
23713
duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
 
23714
        return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
 
23715
}
 
23716
 
 
23717
#line 1 "duk_bi_pointer.c"
 
23718
/*
 
23719
 *  Pointer built-ins
 
23720
 */
 
23721
 
 
23722
/* include removed: duk_internal.h */
 
23723
 
 
23724
/*
 
23725
 *  Constructor
 
23726
 */
 
23727
 
 
23728
int duk_bi_pointer_constructor(duk_context *ctx) {
 
23729
        /* FIXME: this behavior is quite useless now; it would be nice to be able
 
23730
         * to create pointer values from e.g. numbers or strings.  Numbers are
 
23731
         * problematic on 64-bit platforms though.  Hex encoded strings?
 
23732
         */
 
23733
        if (duk_get_top(ctx) == 0) {
 
23734
                duk_push_pointer(ctx, NULL);
 
23735
        } else {
 
23736
                duk_to_pointer(ctx, 0);
 
23737
        }
 
23738
        DUK_ASSERT(duk_is_pointer(ctx, 0));
 
23739
        duk_set_top(ctx, 1);
 
23740
 
 
23741
        if (duk_is_constructor_call(ctx)) {
 
23742
                duk_push_object_helper(ctx,
 
23743
                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
 
23744
                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
 
23745
                                       DUK_BIDX_POINTER_PROTOTYPE);
 
23746
 
 
23747
                /* Pointer object internal value is immutable */
 
23748
                duk_dup(ctx, 0);
 
23749
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
 
23750
        }
 
23751
        /* Note: unbalanced stack on purpose */
 
23752
 
 
23753
        return 1;
 
23754
}
 
23755
 
 
23756
/*
 
23757
 *  toString(), valueOf()
 
23758
 */
 
23759
 
 
23760
int duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
 
23761
        duk_tval *tv;
 
23762
        int to_string = duk_get_magic(ctx);
 
23763
 
 
23764
        duk_push_this(ctx);
 
23765
        tv = duk_require_tval(ctx, -1);
 
23766
        DUK_ASSERT(tv != NULL);
 
23767
 
 
23768
        if (DUK_TVAL_IS_POINTER(tv)) {
 
23769
                /* nop */
 
23770
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
23771
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
23772
                DUK_ASSERT(h != NULL);
 
23773
 
 
23774
                /* Must be a "pointer object", i.e. class "Pointer" */
 
23775
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
 
23776
                        goto type_error;
 
23777
                }
 
23778
 
 
23779
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
23780
        } else {
 
23781
                goto type_error;
 
23782
        }
 
23783
 
 
23784
        if (to_string) {
 
23785
                duk_to_string(ctx, -1);
 
23786
        }
 
23787
        return 1;
 
23788
 
 
23789
 type_error:
 
23790
        return DUK_RET_TYPE_ERROR;
 
23791
}
 
23792
 
 
23793
#line 1 "duk_bi_regexp.c"
 
23794
/*
 
23795
 *  RegExp built-ins
 
23796
 */
 
23797
 
 
23798
/* include removed: duk_internal.h */
 
23799
 
 
23800
#ifdef DUK_USE_REGEXP_SUPPORT
 
23801
 
 
23802
static void duk__get_this_regexp(duk_context *ctx) {
 
23803
        duk_hobject *h;
 
23804
 
 
23805
        duk_push_this(ctx);
 
23806
        h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
 
23807
        DUK_ASSERT(h != NULL);
 
23808
        DUK_UNREF(h);
 
23809
        duk_insert(ctx, 0);  /* prepend regexp to valstack 0 index */
 
23810
}
 
23811
 
 
23812
/* FIXME: much to improve (code size) */
 
23813
duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
 
23814
        duk_hthread *thr = (duk_hthread *) ctx;
 
23815
        duk_hobject *h_pattern;
 
23816
 
 
23817
        DUK_ASSERT_TOP(ctx, 2);
 
23818
        h_pattern = duk_get_hobject(ctx, 0);
 
23819
 
 
23820
        if (!duk_is_constructor_call(ctx) &&
 
23821
            h_pattern != NULL &&
 
23822
            DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
 
23823
            duk_is_undefined(ctx, 1)) {
 
23824
                /* Called as a function, pattern has [[Class]] "RegExp" and
 
23825
                 * flags is undefined -> return object as is.
 
23826
                 */
 
23827
                duk_dup(ctx, 0);
 
23828
                return 1;
 
23829
        }
 
23830
 
 
23831
        /* Else functionality is identical for function call and constructor
 
23832
         * call.
 
23833
         */
 
23834
 
 
23835
        if (h_pattern != NULL &&
 
23836
            DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
 
23837
                if (duk_is_undefined(ctx, 1)) {
 
23838
                        int flag_g, flag_i, flag_m;
 
23839
                        duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
 
23840
                        flag_g = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
 
23841
                        flag_i = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL);
 
23842
                        flag_m = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL);
 
23843
 
 
23844
                        duk_push_sprintf(ctx, "%s%s%s",
 
23845
                                         (flag_g ? "g" : ""),
 
23846
                                         (flag_i ? "i" : ""),
 
23847
                                         (flag_m ? "m" : ""));
 
23848
 
 
23849
                        /* [ ... pattern flags ] */
 
23850
                } else {
 
23851
                        return DUK_RET_TYPE_ERROR;
 
23852
                }
 
23853
        } else {
 
23854
                if (duk_is_undefined(ctx, 0)) {
 
23855
                        duk_push_string(ctx, "");
 
23856
                } else {
 
23857
                        duk_dup(ctx, 0);
 
23858
                        duk_to_string(ctx, -1);
 
23859
                }
 
23860
                if (duk_is_undefined(ctx, 1)) {
 
23861
                        duk_push_string(ctx, "");
 
23862
                } else {
 
23863
                        duk_dup(ctx, 1);
 
23864
                        duk_to_string(ctx, -1);
 
23865
                }
 
23866
 
 
23867
                /* [ ... pattern flags ] */
 
23868
        }
 
23869
 
 
23870
        DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
 
23871
                     duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
23872
 
 
23873
        /* [ ... pattern flags ] */
 
23874
 
 
23875
        duk_regexp_compile(thr);
 
23876
 
 
23877
        /* [ ... bytecode escaped_source ] */
 
23878
 
 
23879
        duk_regexp_create_instance(thr);
 
23880
 
 
23881
        /* [ ... RegExp ] */
 
23882
 
 
23883
        return 1;
 
23884
}
 
23885
 
 
23886
duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
 
23887
        duk__get_this_regexp(ctx);
 
23888
 
 
23889
        /* [ regexp input ] */
 
23890
 
 
23891
        duk_regexp_match((duk_hthread *) ctx);
 
23892
 
 
23893
        /* [ result ] */
 
23894
 
 
23895
        return 1;
 
23896
}
 
23897
 
 
23898
duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
 
23899
        duk__get_this_regexp(ctx);
 
23900
 
 
23901
        /* [ regexp input ] */
 
23902
 
 
23903
        /* result object is created and discarded; wasteful but saves code space */
 
23904
        duk_regexp_match((duk_hthread *) ctx);
 
23905
 
 
23906
        /* [ result ] */
 
23907
 
 
23908
        duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
 
23909
 
 
23910
        return 1;
 
23911
}
 
23912
 
 
23913
duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
 
23914
        duk_hstring *h_bc;
 
23915
        duk_small_int_t re_flags;
 
23916
 
 
23917
#if 0
 
23918
        /* A little tricky string approach to provide the flags string.
 
23919
         * This depends on the specific flag values in duk_regexp.h,
 
23920
         * which needs to be asserted for.  In practice this doesn't
 
23921
         * produce more compact code than the easier approach in use.
 
23922
         */
 
23923
 
 
23924
        const char *flag_strings = "gim\0gi\0gm\0g\0";
 
23925
        duk_uint8_t flag_offsets[8] = {
 
23926
                (duk_uint8_t) 3,   /* flags: ""    */
 
23927
                (duk_uint8_t) 10,  /* flags: "g"   */
 
23928
                (duk_uint8_t) 5,   /* flags: "i"   */
 
23929
                (duk_uint8_t) 4,   /* flags: "gi"  */
 
23930
                (duk_uint8_t) 2,   /* flags: "m"   */
 
23931
                (duk_uint8_t) 7,   /* flags: "gm"  */
 
23932
                (duk_uint8_t) 1,   /* flags: "im"  */
 
23933
                (duk_uint8_t) 0,   /* flags: "gim" */
 
23934
        };
 
23935
        DUK_ASSERT(DUK_RE_FLAG_GLOBAL == 1);
 
23936
        DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE == 2);
 
23937
        DUK_ASSERT(DUK_RE_FLAG_MULTILINE == 4);
 
23938
#endif
 
23939
 
 
23940
        duk__get_this_regexp(ctx);
 
23941
 
 
23942
        /* [ regexp ] */
 
23943
 
 
23944
        duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
 
23945
        duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_BYTECODE);
 
23946
        h_bc = duk_get_hstring(ctx, -1);
 
23947
        DUK_ASSERT(h_bc != NULL);
 
23948
        DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);
 
23949
        DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
 
23950
        DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);
 
23951
        re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
 
23952
 
 
23953
        /* [ regexp source bytecode ] */
 
23954
 
 
23955
#if 1
 
23956
        /* This is a cleaner approach and also produces smaller code than
 
23957
         * the other alternative.
 
23958
         */
 
23959
        duk_push_sprintf(ctx, "/%s/%s%s%s",
 
23960
                         duk_get_string(ctx, -2),
 
23961
                         (re_flags & DUK_RE_FLAG_GLOBAL) ? "g" : "",
 
23962
                         (re_flags & DUK_RE_FLAG_IGNORE_CASE) ? "i" : "",
 
23963
                         (re_flags & DUK_RE_FLAG_MULTILINE) ? "m" : "");
 
23964
#else
 
23965
        /* This should not be necessary because no-one should tamper with the
 
23966
         * regexp bytecode, but is prudent to avoid potential segfaults if that
 
23967
         * were to happen for some reason.
 
23968
         */
 
23969
        re_flags &= 0x07;
 
23970
        DUK_ASSERT(re_flags >= 0 && re_flags <= 7);  /* three flags */
 
23971
        duk_push_sprintf(ctx, "/%s/%s",
 
23972
                         duk_get_string(ctx, -2),
 
23973
                         flag_strings + flag_offsets[re_flags]);
 
23974
#endif
 
23975
 
 
23976
        return 1;
 
23977
}
 
23978
 
 
23979
#else  /* DUK_USE_REGEXP_SUPPORT */
 
23980
 
 
23981
duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
 
23982
        DUK_UNREF(ctx);
 
23983
        return DUK_RET_UNSUPPORTED_ERROR;
 
23984
}
 
23985
 
 
23986
duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
 
23987
        DUK_UNREF(ctx);
 
23988
        return DUK_RET_UNSUPPORTED_ERROR;
 
23989
}
 
23990
 
 
23991
duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
 
23992
        DUK_UNREF(ctx);
 
23993
        return DUK_RET_UNSUPPORTED_ERROR;
 
23994
}
 
23995
 
 
23996
duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
 
23997
        DUK_UNREF(ctx);
 
23998
        return DUK_RET_UNSUPPORTED_ERROR;
 
23999
}
 
24000
 
 
24001
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24002
#line 1 "duk_bi_string.c"
 
24003
/*
 
24004
 *  String built-ins
 
24005
 */
 
24006
 
 
24007
/* FIXME: There are now many assumptions here that string character length
 
24008
 * fits into signed 32 bits, e.g.: type choices, int clamping helpers.
 
24009
 */
 
24010
 
 
24011
/* include removed: duk_internal.h */
 
24012
 
 
24013
/*
 
24014
 *  Constructor
 
24015
 */
 
24016
 
 
24017
duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
 
24018
        /* String constructor needs to distinguish between an argument not given at all
 
24019
         * vs. given as 'undefined'.  We're a vararg function to handle this properly.
 
24020
         */
 
24021
 
 
24022
        if (duk_get_top(ctx) == 0) {
 
24023
                duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
24024
        } else {
 
24025
                duk_to_string(ctx, 0);
 
24026
        }
 
24027
        DUK_ASSERT(duk_is_string(ctx, 0));
 
24028
        duk_set_top(ctx, 1);
 
24029
 
 
24030
        if (duk_is_constructor_call(ctx)) {
 
24031
                duk_push_object_helper(ctx,
 
24032
                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
 
24033
                                       DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ |
 
24034
                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING),
 
24035
                                       DUK_BIDX_STRING_PROTOTYPE);
 
24036
 
 
24037
                /* String object internal value is immutable */
 
24038
                duk_dup(ctx, 0);
 
24039
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
 
24040
        }
 
24041
        /* Note: unbalanced stack on purpose */
 
24042
 
 
24043
        return 1;
 
24044
}
 
24045
 
 
24046
duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
 
24047
        duk_hthread *thr = (duk_hthread *) ctx;
 
24048
        duk_hbuffer_dynamic *h;
 
24049
        duk_idx_t i, n;
 
24050
        duk_ucodepoint_t cp;
 
24051
 
 
24052
        /* XXX: It would be nice to build the string directly but ToUint16()
 
24053
         * coercion is needed so a generic helper would not be very
 
24054
         * helpful (perhaps coerce the value stack first here and then
 
24055
         * build a string from a duk_tval number sequence in one go?).
 
24056
         */
 
24057
 
 
24058
        n = duk_get_top(ctx);
 
24059
        duk_push_dynamic_buffer(ctx, 0);  /* XXX: initial spare size estimate from 'n' */
 
24060
        h = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
24061
 
 
24062
        for (i = 0; i < n; i++) {
 
24063
                cp = duk_to_uint16(ctx, i);
 
24064
                duk_hbuffer_append_cesu8(thr, h, cp);
 
24065
        }
 
24066
 
 
24067
        duk_to_string(ctx, -1);
 
24068
        return 1;
 
24069
}
 
24070
 
 
24071
/*
 
24072
 *  toString(), valueOf()
 
24073
 */
 
24074
 
 
24075
duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
 
24076
        duk_tval *tv;
 
24077
 
 
24078
        duk_push_this(ctx);
 
24079
        tv = duk_require_tval(ctx, -1);
 
24080
        DUK_ASSERT(tv != NULL);
 
24081
 
 
24082
        if (DUK_TVAL_IS_STRING(tv)) {
 
24083
                /* return as is */
 
24084
                return 1;
 
24085
        } else if (DUK_TVAL_IS_OBJECT(tv)) {
 
24086
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
24087
                DUK_ASSERT(h != NULL);
 
24088
 
 
24089
                /* Must be a "string object", i.e. class "String" */
 
24090
                if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
 
24091
                        goto type_error;
 
24092
                }
 
24093
 
 
24094
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
 
24095
                DUK_ASSERT(duk_is_string(ctx, -1));
 
24096
 
 
24097
                return 1;
 
24098
        } else {
 
24099
                goto type_error;
 
24100
        }
 
24101
 
 
24102
        /* never here, but fall through */
 
24103
 
 
24104
 type_error:
 
24105
        return DUK_RET_TYPE_ERROR;
 
24106
}
 
24107
 
 
24108
/*
 
24109
 *  Character and charcode access
 
24110
 */
 
24111
 
 
24112
duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
 
24113
        duk_int_t pos;  /* FIXME: type, duk_to_int() needs to be fixed */
 
24114
 
 
24115
        /* FIXME: faster implementation */
 
24116
        /* FIXME: handling int values outside C int range, currently
 
24117
         * duk_to_int() coerces to min/max int, so this works passably.
 
24118
         */
 
24119
 
 
24120
        (void) duk_push_this_coercible_to_string(ctx);
 
24121
        pos = duk_to_int(ctx, 0);
 
24122
        duk_substring(ctx, -1, pos, pos + 1);
 
24123
        return 1;
 
24124
}
 
24125
 
 
24126
duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
 
24127
        duk_hthread *thr = (duk_hthread *) ctx;
 
24128
        duk_int_t pos;  /* FIXME: type, duk_to_int() needs to be fixed */
 
24129
        duk_hstring *h;
 
24130
        int clamped;  /* FIXME: type */
 
24131
 
 
24132
        /* FIXME: faster implementation */
 
24133
 
 
24134
        DUK_DDDPRINT("arg=%!T", duk_get_tval(ctx, 0));
 
24135
 
 
24136
        h = duk_push_this_coercible_to_string(ctx);
 
24137
        DUK_ASSERT(h != NULL);
 
24138
 
 
24139
        pos = duk_to_int_clamped_raw(ctx,
 
24140
                                     0 /*index*/,
 
24141
                                     0 /*min(incl)*/,
 
24142
                                     DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
 
24143
                                     &clamped /*clamped*/);
 
24144
        if (clamped) {
 
24145
                duk_push_number(ctx, DUK_DOUBLE_NAN);
 
24146
                return 1;
 
24147
        }
 
24148
 
 
24149
        duk_push_u32(ctx, (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos));
 
24150
        return 1;
 
24151
}
 
24152
 
 
24153
/*
 
24154
 *  substring(), substr(), slice()
 
24155
 */
 
24156
 
 
24157
/* XXX: any chance of merging these three similar but still slightly
 
24158
 * different algorithms so that footprint would be reduced?
 
24159
 */
 
24160
 
 
24161
duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
 
24162
        duk_hstring *h;
 
24163
        duk_int_t start_pos, end_pos;
 
24164
        duk_int_t len;
 
24165
 
 
24166
        h = duk_push_this_coercible_to_string(ctx);
 
24167
        DUK_ASSERT(h != NULL);
 
24168
        len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
 
24169
 
 
24170
        /* [ start end str ] */
 
24171
 
 
24172
        start_pos = duk_to_int_clamped(ctx, 0, 0, len);
 
24173
        if (duk_is_undefined(ctx, 1)) {
 
24174
                end_pos = len;
 
24175
        } else {
 
24176
                end_pos = duk_to_int_clamped(ctx, 1, 0, len);
 
24177
        }
 
24178
        DUK_ASSERT(start_pos >= 0 && start_pos <= len);
 
24179
        DUK_ASSERT(end_pos >= 0 && end_pos <= len);
 
24180
 
 
24181
        if (start_pos > end_pos) {
 
24182
                duk_int_t tmp = start_pos;
 
24183
                start_pos = end_pos;
 
24184
                end_pos = tmp;
 
24185
        }
 
24186
 
 
24187
        DUK_ASSERT(end_pos >= start_pos);
 
24188
 
 
24189
        duk_substring(ctx, -1, (size_t) start_pos, (size_t) end_pos);
 
24190
        return 1;
 
24191
}
 
24192
 
 
24193
#ifdef DUK_USE_SECTION_B
 
24194
duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
 
24195
        duk_hstring *h;
 
24196
        duk_int_t start_pos, end_pos;
 
24197
        duk_int_t len;
 
24198
 
 
24199
        /* Unlike non-obsolete String calls, substr() algorithm in E5.1
 
24200
         * specification will happily coerce undefined and null to strings
 
24201
         * ("undefined" and "null").
 
24202
         */
 
24203
        duk_push_this(ctx);
 
24204
        h = duk_to_hstring(ctx, -1);
 
24205
        DUK_ASSERT(h != NULL);
 
24206
        len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
 
24207
 
 
24208
        /* [ start length str ] */
 
24209
 
 
24210
        /* The implementation for computing of start_pos and end_pos differs
 
24211
         * from the standard algorithm, but is intended to result in the exactly
 
24212
         * same behavior.  This is not always obvious.
 
24213
         */
 
24214
 
 
24215
        /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
 
24216
        start_pos = duk_to_int_clamped(ctx, 0, -len, len);
 
24217
        if (start_pos < 0) {
 
24218
                start_pos = len + start_pos;
 
24219
        }
 
24220
        DUK_ASSERT(start_pos >= 0 && start_pos <= len);
 
24221
 
 
24222
        /* combines steps 3, 6; step 7 is not needed */
 
24223
        if (duk_is_undefined(ctx, 1)) {
 
24224
                end_pos = len;
 
24225
        } else {
 
24226
                DUK_ASSERT(start_pos <= len);
 
24227
                end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
 
24228
        }
 
24229
        DUK_ASSERT(start_pos >= 0 && start_pos <= len);
 
24230
        DUK_ASSERT(end_pos >= 0 && end_pos <= len);
 
24231
        DUK_ASSERT(end_pos >= start_pos);
 
24232
 
 
24233
        duk_substring(ctx, -1, (size_t) start_pos, (size_t) end_pos);
 
24234
        return 1;
 
24235
}
 
24236
#else  /* DUK_USE_SECTION_B */
 
24237
duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
 
24238
        DUK_UNREF(ctx);
 
24239
        return DUK_RET_UNSUPPORTED_ERROR;
 
24240
}
 
24241
#endif  /* DUK_USE_SECTION_B */
 
24242
 
 
24243
duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
 
24244
        duk_hstring *h;
 
24245
        duk_int_t start_pos, end_pos;
 
24246
        duk_int_t len;
 
24247
 
 
24248
        h = duk_push_this_coercible_to_string(ctx);
 
24249
        DUK_ASSERT(h != NULL);
 
24250
        len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
 
24251
 
 
24252
        /* [ start end str ] */
 
24253
 
 
24254
        start_pos = duk_to_int_clamped(ctx, 0, -len, len);
 
24255
        if (start_pos < 0) {
 
24256
                start_pos = len + start_pos;
 
24257
        }
 
24258
        if (duk_is_undefined(ctx, 1)) {
 
24259
                end_pos = len;
 
24260
        } else {
 
24261
                end_pos = duk_to_int_clamped(ctx, 1, -len, len);
 
24262
                if (end_pos < 0) {
 
24263
                        end_pos = len + end_pos;
 
24264
                }
 
24265
        }
 
24266
        DUK_ASSERT(start_pos >= 0 && start_pos <= len);
 
24267
        DUK_ASSERT(end_pos >= 0 && end_pos <= len);
 
24268
 
 
24269
        if (end_pos < start_pos) {
 
24270
                end_pos = start_pos;
 
24271
        }
 
24272
 
 
24273
        DUK_ASSERT(end_pos >= start_pos);
 
24274
 
 
24275
        duk_substring(ctx, -1, (size_t) start_pos, (size_t) end_pos);
 
24276
        return 1;
 
24277
}
 
24278
 
 
24279
/*
 
24280
 *  Case conversion
 
24281
 */
 
24282
 
 
24283
duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
 
24284
        duk_hthread *thr = (duk_hthread *) ctx;
 
24285
        duk_small_int_t uppercase = duk_get_magic(ctx);
 
24286
 
 
24287
        (void) duk_push_this_coercible_to_string(ctx);
 
24288
        duk_unicode_case_convert_string(thr, uppercase);
 
24289
        return 1;
 
24290
}
 
24291
 
 
24292
/*
 
24293
 *  indexOf() and lastIndexOf()
 
24294
 */
 
24295
 
 
24296
duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
 
24297
        duk_hthread *thr = (duk_hthread *) ctx;
 
24298
        duk_hstring *h_this;
 
24299
        duk_hstring *h_search;
 
24300
        duk_int_t clen_this;
 
24301
        duk_int_t cpos;
 
24302
        duk_int_t bpos;
 
24303
        duk_uint8_t *p_start, *p_end, *p;
 
24304
        duk_uint8_t *q_start;
 
24305
        duk_size_t q_blen;  /* FIXME: type inconsistency (clen_this is duk_int_t) */
 
24306
        duk_uint8_t firstbyte;
 
24307
        duk_uint8_t t;
 
24308
        duk_small_int_t is_lastindexof = duk_get_magic(ctx);  /* 0=indexOf, 1=lastIndexOf */
 
24309
 
 
24310
        h_this = duk_push_this_coercible_to_string(ctx);
 
24311
        DUK_ASSERT(h_this != NULL);
 
24312
        clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
 
24313
 
 
24314
        h_search = duk_to_hstring(ctx, 0);
 
24315
        DUK_ASSERT(h_search != NULL);
 
24316
        q_start = DUK_HSTRING_GET_DATA(h_search);
 
24317
        q_blen = (size_t) DUK_HSTRING_GET_BYTELEN(h_search);
 
24318
 
 
24319
        duk_to_number(ctx, 1);
 
24320
        if (duk_is_nan(ctx, 1) && is_lastindexof) {
 
24321
                /* indexOf: NaN should cause pos to be zero.
 
24322
                 * lastIndexOf: NaN should cause pos to be +Infinity
 
24323
                 * (and later be clamped to len).
 
24324
                 */
 
24325
                cpos = clen_this;
 
24326
        } else {
 
24327
                cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
 
24328
        }
 
24329
 
 
24330
        /* Empty searchstring always matches; cpos must be clamped here. */
 
24331
        if (q_blen == 0) {
 
24332
                duk_push_int(ctx, cpos);
 
24333
                return 1;
 
24334
        }
 
24335
 
 
24336
        bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
 
24337
 
 
24338
        p_start = DUK_HSTRING_GET_DATA(h_this);
 
24339
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
 
24340
        p = p_start + bpos;
 
24341
 
 
24342
        /* This loop is optimized for size.  For speed, there should be
 
24343
         * two separate loops, and we should ensure that memcmp() can be
 
24344
         * used without an extra "will searchstring fit" check.  Doing
 
24345
         * the preconditioning for 'p' and 'p_end' is easy but cpos
 
24346
         * must be updated if 'p' is wound back (backward scanning).
 
24347
         */
 
24348
 
 
24349
        firstbyte = q_start[0];  /* leading byte of match string */
 
24350
        while (p <= p_end && p >= p_start) {
 
24351
                t = *p;
 
24352
 
 
24353
                /* For Ecmascript strings, this check can only match for
 
24354
                 * initial UTF-8 bytes (not continuation bytes).  For other
 
24355
                 * strings all bets are off.
 
24356
                 */
 
24357
 
 
24358
                if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= q_blen)) {
 
24359
                        DUK_ASSERT(q_blen > 0);  /* no issues with memcmp() zero size, even if broken */
 
24360
                        if (DUK_MEMCMP(p, q_start, q_blen) == 0) {
 
24361
                                duk_push_int(ctx, cpos);
 
24362
                                return 1;
 
24363
                        }
 
24364
                }
 
24365
 
 
24366
                /* track cpos while scanning */
 
24367
                if (is_lastindexof) {
 
24368
                        /* when going backwards, we decrement cpos 'early';
 
24369
                         * 'p' may point to a continuation byte of the char
 
24370
                         * at offset 'cpos', but that's OK because we'll
 
24371
                         * backtrack all the way to the initial byte.
 
24372
                         */
 
24373
                        if ((t & 0xc0) != 0x80) {
 
24374
                                cpos--;
 
24375
                        }
 
24376
                        p--;
 
24377
                } else {
 
24378
                        if ((t & 0xc0) != 0x80) {
 
24379
                                cpos++;
 
24380
                        }
 
24381
                        p++;
 
24382
                }
 
24383
        }
 
24384
 
 
24385
        /* Not found.  Empty string case is handled specially above. */
 
24386
        duk_push_int(ctx, -1);
 
24387
        return 1;
 
24388
}
 
24389
 
 
24390
/*
 
24391
 *  replace()
 
24392
 */
 
24393
 
 
24394
/* FIXME: the current implementation works but is quite clunky; it compiles
 
24395
 * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
 
24396
 * shared helpers, etc).
 
24397
 */
 
24398
 
 
24399
/* FIXME: some ideas for refactoring:
 
24400
 * - a primitive to convert a string into a regexp matcher (reduces matching
 
24401
 *   code at the cost of making matching much slower)
 
24402
 * - use replace() as a basic helper for match() and split(), which are both
 
24403
 *   much simpler
 
24404
 * - API call to get_prop and to_boolean
 
24405
 */
 
24406
 
 
24407
duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
 
24408
        duk_hthread *thr = (duk_hthread *) ctx;
 
24409
        duk_hstring *h_input;
 
24410
        duk_hstring *h_repl;
 
24411
        duk_hstring *h_match;
 
24412
        duk_hstring *h_search;
 
24413
        duk_hobject *h_re;
 
24414
        duk_hbuffer_dynamic *h_buf;
 
24415
#ifdef DUK_USE_REGEXP_SUPPORT
 
24416
        duk_small_int_t is_regexp;
 
24417
        duk_small_int_t is_global;
 
24418
#endif
 
24419
        duk_small_int_t is_repl_func;
 
24420
        duk_uint32_t match_start_coff, match_start_boff;
 
24421
#ifdef DUK_USE_REGEXP_SUPPORT
 
24422
        duk_small_int_t match_caps;
 
24423
#endif
 
24424
        duk_uint32_t prev_match_end_boff;
 
24425
        duk_uint8_t *r_start, *r_end, *r;   /* repl string scan */
 
24426
 
 
24427
        DUK_ASSERT_TOP(ctx, 2);
 
24428
        h_input = duk_push_this_coercible_to_string(ctx);
 
24429
        DUK_ASSERT(h_input != NULL);
 
24430
        duk_push_dynamic_buffer(ctx, 0);
 
24431
        h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
24432
        DUK_ASSERT(h_buf != NULL);
 
24433
        DUK_ASSERT_TOP(ctx, 4);
 
24434
 
 
24435
        /* stack[0] = search value
 
24436
         * stack[1] = replace value
 
24437
         * stack[2] = input string
 
24438
         * stack[3] = result buffer
 
24439
         */
 
24440
 
 
24441
        h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
 
24442
        if (h_re) {
 
24443
#ifdef DUK_USE_REGEXP_SUPPORT
 
24444
                is_regexp = 1;
 
24445
                is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
 
24446
 
 
24447
                if (is_global) {
 
24448
                        /* start match from beginning */
 
24449
                        duk_push_int(ctx, 0);
 
24450
                        duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
24451
                }
 
24452
#else  /* DUK_USE_REGEXP_SUPPORT */
 
24453
                return DUK_RET_UNSUPPORTED_ERROR;
 
24454
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24455
        } else {
 
24456
                duk_to_string(ctx, 0);
 
24457
#ifdef DUK_USE_REGEXP_SUPPORT
 
24458
                is_regexp = 0;
 
24459
                is_global = 0;
 
24460
#endif
 
24461
        }
 
24462
 
 
24463
        if (duk_is_function(ctx, 1)) {
 
24464
                is_repl_func = 1;
 
24465
                r_start = NULL;
 
24466
                r_end = NULL;
 
24467
        } else {
 
24468
                is_repl_func = 0;
 
24469
                h_repl = duk_to_hstring(ctx, 1);
 
24470
                DUK_ASSERT(h_repl != NULL);
 
24471
                r_start = DUK_HSTRING_GET_DATA(h_repl);
 
24472
                r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
 
24473
        }
 
24474
 
 
24475
        prev_match_end_boff = 0;
 
24476
 
 
24477
        for (;;) {
 
24478
                /*
 
24479
                 *  If matching with a regexp:
 
24480
                 *    - non-global RegExp: lastIndex not touched on a match, zeroed
 
24481
                 *      on a non-match
 
24482
                 *    - global RegExp: on match, lastIndex will be updated by regexp
 
24483
                 *      executor to point to next char after the matching part (so that
 
24484
                 *      characters in the matching part are not matched again)
 
24485
                 *
 
24486
                 *  If matching with a string:
 
24487
                 *    - always non-global match, find first occurrence
 
24488
                 *
 
24489
                 *  We need:
 
24490
                 *    - The character offset of start-of-match for the replacer function
 
24491
                 *    - The byte offsets for start-of-match and end-of-match to implement
 
24492
                 *      the replacement values $&, $`, and $', and to copy non-matching
 
24493
                 *      input string portions (including header and trailer) verbatim.
 
24494
                 *
 
24495
                 *  NOTE: the E5.1 specification is a bit vague how the RegExp should
 
24496
                 *  behave in the replacement process; e.g. is matching done first for
 
24497
                 *  all matches (in the global RegExp case) before any replacer calls
 
24498
                 *  are made?  See: test-bi-string-proto-replace.js for discussion.
 
24499
                 */
 
24500
 
 
24501
                DUK_ASSERT_TOP(ctx, 4);
 
24502
 
 
24503
#ifdef DUK_USE_REGEXP_SUPPORT
 
24504
                if (is_regexp) {
 
24505
                        duk_dup(ctx, 0);
 
24506
                        duk_dup(ctx, 2);
 
24507
                        duk_regexp_match(thr);  /* [ ... regexp input ] -> [ res_obj ] */
 
24508
                        if (!duk_is_object(ctx, -1)) {
 
24509
                                duk_pop(ctx);
 
24510
                                break;
 
24511
                        }
 
24512
 
 
24513
                        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
 
24514
                        DUK_ASSERT(duk_is_number(ctx, -1));
 
24515
                        match_start_coff = duk_get_int(ctx, -1);
 
24516
                        duk_pop(ctx);
 
24517
 
 
24518
                        duk_get_prop_index(ctx, -1, 0);
 
24519
                        DUK_ASSERT(duk_is_string(ctx, -1));
 
24520
                        h_match = duk_get_hstring(ctx, -1);
 
24521
                        DUK_ASSERT(h_match != NULL);
 
24522
                        duk_pop(ctx);  /* h_match is borrowed, remains reachable through match_obj */
 
24523
 
 
24524
                        if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
 
24525
                                /* This should be equivalent to match() algorithm step 8.f.iii.2:
 
24526
                                 * detect an empty match and allow it, but don't allow it twice.
 
24527
                                 */
 
24528
                                duk_uint32_t last_index;
 
24529
 
 
24530
                                duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
24531
                                last_index = duk_get_int(ctx, -1);  /* FIXME: duk_get_uint32() */
 
24532
                                DUK_DDDPRINT("empty match, bump lastIndex: %d -> %d", last_index, last_index + 1);
 
24533
                                duk_pop(ctx);
 
24534
                                duk_push_int(ctx, last_index + 1);
 
24535
                                duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
24536
                        }
 
24537
 
 
24538
                        match_caps = duk_get_length(ctx, -1);
 
24539
                } else {
 
24540
#else  /* DUK_USE_REGEXP_SUPPORT */
 
24541
                {  /* unconditionally */
 
24542
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24543
                        duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
 
24544
                        duk_uint8_t *q_start;               /* match string */
 
24545
                        duk_size_t q_blen;
 
24546
 
 
24547
#ifdef DUK_USE_REGEXP_SUPPORT
 
24548
                        DUK_ASSERT(!is_global);  /* single match always */
 
24549
#endif
 
24550
 
 
24551
                        p_start = DUK_HSTRING_GET_DATA(h_input);
 
24552
                        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
 
24553
                        p = p_start;
 
24554
 
 
24555
                        h_search = duk_get_hstring(ctx, 0);
 
24556
                        DUK_ASSERT(h_search != NULL);
 
24557
                        q_start = DUK_HSTRING_GET_DATA(h_search);
 
24558
                        q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
 
24559
 
 
24560
                        p_end -= q_blen;  /* ensure full memcmp() fits in while */
 
24561
 
 
24562
                        match_start_coff = 0;
 
24563
 
 
24564
                        while (p <= p_end) {
 
24565
                                DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
 
24566
                                if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) {
 
24567
                                        duk_dup(ctx, 0);
 
24568
                                        h_match = duk_get_hstring(ctx, -1);
 
24569
                                        DUK_ASSERT(h_match != NULL);
 
24570
#ifdef DUK_USE_REGEXP_SUPPORT
 
24571
                                        match_caps = 0;
 
24572
#endif
 
24573
                                        goto found;
 
24574
                                }
 
24575
 
 
24576
                                /* track utf-8 non-continuation bytes */
 
24577
                                if ((p[0] & 0xc0) != 0x80) {
 
24578
                                        match_start_coff++;
 
24579
                                }
 
24580
                                p++;
 
24581
                        }
 
24582
 
 
24583
                        /* not found */
 
24584
                        break;
 
24585
                }
 
24586
         found:
 
24587
 
 
24588
                /* stack[0] = search value
 
24589
                 * stack[1] = replace value
 
24590
                 * stack[2] = input string
 
24591
                 * stack[3] = result buffer
 
24592
                 * stack[4] = regexp match OR match string
 
24593
                 */
 
24594
 
 
24595
                match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
 
24596
 
 
24597
                duk_hbuffer_append_bytes(thr,
 
24598
                                         h_buf,
 
24599
                                         DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
 
24600
                                         (size_t) (match_start_boff - prev_match_end_boff));
 
24601
 
 
24602
                prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
 
24603
 
 
24604
                if (is_repl_func) {
 
24605
                        duk_idx_t idx_args;
 
24606
                        duk_hstring *h_repl;
 
24607
 
 
24608
                        /* regexp res_obj is at index 4 */
 
24609
 
 
24610
                        duk_dup(ctx, 1);
 
24611
                        idx_args = duk_get_top(ctx);
 
24612
 
 
24613
#ifdef DUK_USE_REGEXP_SUPPORT
 
24614
                        if (is_regexp) {
 
24615
                                duk_int_t idx;
 
24616
                                duk_require_stack(ctx, match_caps + 2);
 
24617
                                for (idx = 0; idx < match_caps; idx++) {
 
24618
                                        /* match followed by capture(s) */
 
24619
                                        duk_get_prop_index(ctx, 4, idx);
 
24620
                                }
 
24621
                        } else {
 
24622
#else  /* DUK_USE_REGEXP_SUPPORT */
 
24623
                        {  /* unconditionally */
 
24624
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24625
                                /* match == search string, by definition */
 
24626
                                duk_dup(ctx, 0);
 
24627
                        }
 
24628
                        duk_push_int(ctx, match_start_coff);
 
24629
                        duk_dup(ctx, 2);
 
24630
 
 
24631
                        /* [ ... replacer match [captures] match_char_offset input ] */
 
24632
 
 
24633
                        duk_call(ctx, duk_get_top(ctx) - idx_args);
 
24634
                        h_repl = duk_to_hstring(ctx, -1);  /* -> [ ... repl_value ] */
 
24635
                        DUK_ASSERT(h_repl != NULL);
 
24636
                        duk_hbuffer_append_hstring(thr, h_buf, h_repl);
 
24637
                        duk_pop(ctx);  /* repl_value */
 
24638
                } else {
 
24639
                        r = r_start;
 
24640
 
 
24641
                        while (r < r_end) {
 
24642
                                duk_int_t ch1;
 
24643
                                duk_int_t ch2;
 
24644
#ifdef DUK_USE_REGEXP_SUPPORT
 
24645
                                duk_int_t ch3;
 
24646
#endif
 
24647
                                duk_size_t left;
 
24648
 
 
24649
                                ch1 = *r++;
 
24650
                                if (ch1 != (duk_int_t) '$') {
 
24651
                                        goto repl_write;
 
24652
                                }
 
24653
                                left = r_end - r;
 
24654
 
 
24655
                                if (left <= 0) {
 
24656
                                        goto repl_write;
 
24657
                                }
 
24658
 
 
24659
                                ch2 = r[0];
 
24660
                                switch (ch2) {
 
24661
                                case (duk_int_t) '$': {
 
24662
                                        ch1 = (1 << 8) + (duk_int_t) '$';
 
24663
                                        goto repl_write;
 
24664
                                }
 
24665
                                case (duk_int_t) '&': {
 
24666
                                        duk_hbuffer_append_hstring(thr, h_buf, h_match);
 
24667
                                        r++;
 
24668
                                        continue;
 
24669
                                }
 
24670
                                case (duk_int_t) '`': {
 
24671
                                        duk_hbuffer_append_bytes(thr,
 
24672
                                                                 h_buf,
 
24673
                                                                 DUK_HSTRING_GET_DATA(h_input),
 
24674
                                                                 match_start_boff);
 
24675
                                        r++;
 
24676
                                        continue;
 
24677
                                }
 
24678
                                case (duk_int_t) '\'': {
 
24679
                                        duk_uint32_t match_end_boff;
 
24680
 
 
24681
                                        /* Use match charlen instead of bytelen, just in case the input and
 
24682
                                         * match codepoint encodings would have different lengths.
 
24683
                                         */
 
24684
                                        match_end_boff = duk_heap_strcache_offset_char2byte(thr,
 
24685
                                                                                            h_input,
 
24686
                                                                                            match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
 
24687
 
 
24688
                                        duk_hbuffer_append_bytes(thr,
 
24689
                                                                 h_buf,
 
24690
                                                                 DUK_HSTRING_GET_DATA(h_input) + match_end_boff,
 
24691
                                                                 DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
 
24692
                                        r++;
 
24693
                                        continue;
 
24694
                                }
 
24695
                                default: {
 
24696
#ifdef DUK_USE_REGEXP_SUPPORT
 
24697
                                        duk_int_t capnum, captmp, capadv;
 
24698
                                        /* FIXME: optional check, match_caps is zero if no regexp,
 
24699
                                         * so dollar will be interpreted literally anyway.
 
24700
                                         */
 
24701
 
 
24702
                                        if (!is_regexp) {
 
24703
                                                goto repl_write;
 
24704
                                        }
 
24705
 
 
24706
                                        if (!(ch2 >= (duk_int_t) '0' && ch2 <= (duk_int_t) '9')) {
 
24707
                                                goto repl_write;
 
24708
                                        }
 
24709
                                        capnum = ch2 - (duk_int_t) '0';
 
24710
                                        capadv = 1;
 
24711
 
 
24712
                                        if (left >= 2) {
 
24713
                                                ch3 = r[1];
 
24714
                                                if (ch3 >= (duk_int_t) '0' && ch3 <= (duk_int_t) '9') {
 
24715
                                                        captmp = capnum * 10 + (ch3 - (duk_int_t) '0');
 
24716
                                                        if (captmp < match_caps) {
 
24717
                                                                capnum = captmp;
 
24718
                                                                capadv = 2;
 
24719
                                                        }
 
24720
                                                }
 
24721
                                        }
 
24722
 
 
24723
                                        if (capnum > 0 && capnum < match_caps) {
 
24724
                                                DUK_ASSERT(is_regexp != 0);  /* match_caps == 0 without regexps */
 
24725
 
 
24726
                                                /* regexp res_obj is at offset 4 */
 
24727
                                                duk_get_prop_index(ctx, 4, capnum);
 
24728
                                                if (duk_is_string(ctx, -1)) {
 
24729
                                                        DUK_ASSERT(duk_get_hstring(ctx, -1) != NULL);
 
24730
                                                        duk_hbuffer_append_hstring(thr, h_buf, duk_get_hstring(ctx, -1));
 
24731
                                                } else {
 
24732
                                                        /* undefined -> skip (replaced with empty) */
 
24733
                                                }
 
24734
                                                duk_pop(ctx);
 
24735
                                                r += capadv;
 
24736
                                                continue;
 
24737
                                        } else {
 
24738
                                                goto repl_write;
 
24739
                                        }
 
24740
#else  /* DUK_USE_REGEXP_SUPPORT */
 
24741
                                        goto repl_write;  /* unconditionally */
 
24742
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24743
                                }  /* default case */
 
24744
                                }  /* switch (ch2) */
 
24745
 
 
24746
                         repl_write:
 
24747
                                /* ch1 = (r_increment << 8) + byte */
 
24748
                                duk_hbuffer_append_byte(thr, h_buf, (duk_uint8_t) (ch1 & 0xff));
 
24749
                                r += ch1 >> 8;
 
24750
                        }  /* while repl */
 
24751
                }  /* if (is_repl_func) */
 
24752
 
 
24753
                duk_pop(ctx);  /* pop regexp res_obj or match string */
 
24754
 
 
24755
#ifdef DUK_USE_REGEXP_SUPPORT
 
24756
                if (!is_global) {
 
24757
#else
 
24758
                {  /* unconditionally; is_global==0 */
 
24759
#endif
 
24760
                        break;
 
24761
                }
 
24762
        }
 
24763
 
 
24764
        /* trailer */
 
24765
        duk_hbuffer_append_bytes(thr,
 
24766
                                 h_buf,
 
24767
                                 DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
 
24768
                                 (size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
 
24769
 
 
24770
        DUK_ASSERT_TOP(ctx, 4);
 
24771
        duk_to_string(ctx, -1);
 
24772
        return 1;
 
24773
}
 
24774
 
 
24775
/*
 
24776
 *  split()
 
24777
 */
 
24778
 
 
24779
/* FIXME: very messy now, but works; clean up, remove unused variables (nomimally
 
24780
 * used so compiler doesn't complain).
 
24781
 */
 
24782
 
 
24783
int duk_bi_string_prototype_split(duk_context *ctx) {
 
24784
        duk_hthread *thr = (duk_hthread *) ctx;
 
24785
        duk_hstring *h_input;
 
24786
        duk_hstring *h_sep;
 
24787
        duk_uint32_t limit;
 
24788
        duk_uint32_t arr_idx;
 
24789
#ifdef DUK_USE_REGEXP_SUPPORT
 
24790
        duk_small_int_t is_regexp;
 
24791
#endif
 
24792
        duk_small_int_t matched;  /* set to 1 if any match exists (needed for empty input special case) */
 
24793
        duk_uint32_t prev_match_end_coff, prev_match_end_boff;
 
24794
        duk_uint32_t match_start_boff, match_start_coff;
 
24795
        duk_uint32_t match_end_boff, match_end_coff;
 
24796
 
 
24797
        DUK_UNREF(thr);
 
24798
 
 
24799
        h_input = duk_push_this_coercible_to_string(ctx);
 
24800
        DUK_ASSERT(h_input != NULL);
 
24801
 
 
24802
        duk_push_array(ctx);
 
24803
 
 
24804
        if (duk_is_undefined(ctx, 1)) {
 
24805
                limit = 0xffffffffUL;
 
24806
        } else {
 
24807
                limit = duk_to_uint32(ctx, 1);
 
24808
        }
 
24809
 
 
24810
        if (limit == 0) {
 
24811
                return 1;
 
24812
        }
 
24813
 
 
24814
        /* If the separator is a RegExp, make a "clone" of it.  The specification
 
24815
         * algorithm calls [[Match]] directly for specific indices; we emulate this
 
24816
         * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
 
24817
         * which will use global-style matching even when the RegExp itself is non-global.
 
24818
         */
 
24819
 
 
24820
        if (duk_is_undefined(ctx, 0)) {
 
24821
                /* The spec algorithm first does "R = ToString(separator)" before checking
 
24822
                 * whether separator is undefined.  Since this is side effect free, we can
 
24823
                 * skip the ToString() here.
 
24824
                 */
 
24825
                duk_dup(ctx, 2);
 
24826
                duk_put_prop_index(ctx, 3, 0);
 
24827
                return 1;
 
24828
        } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
 
24829
#ifdef DUK_USE_REGEXP_SUPPORT
 
24830
                duk_push_hobject(ctx, thr->builtins[DUK_BIDX_REGEXP_CONSTRUCTOR]);
 
24831
                duk_dup(ctx, 0);
 
24832
                duk_new(ctx, 1);  /* [ ... RegExp val ] -> [ ... res ] */
 
24833
                duk_replace(ctx, 0);
 
24834
                /* lastIndex is initialized to zero by new RegExp() */
 
24835
                is_regexp = 1;
 
24836
#else
 
24837
                return DUK_RET_UNSUPPORTED_ERROR;
 
24838
#endif
 
24839
        } else {
 
24840
                duk_to_string(ctx, 0);
 
24841
#ifdef DUK_USE_REGEXP_SUPPORT
 
24842
                is_regexp = 0;
 
24843
#endif
 
24844
        }
 
24845
 
 
24846
        /* stack[0] = separator (string or regexp)
 
24847
         * stack[1] = limit
 
24848
         * stack[2] = input string
 
24849
         * stack[3] = result array
 
24850
         */
 
24851
 
 
24852
        prev_match_end_boff = 0;
 
24853
        prev_match_end_coff = 0;
 
24854
        arr_idx = 0;
 
24855
        matched = 0;
 
24856
 
 
24857
        for (;;) {
 
24858
                /*
 
24859
                 *  The specification uses RegExp [[Match]] to attempt match at specific
 
24860
                 *  offsets.  We don't have such a primitive, so we use an actual RegExp
 
24861
                 *  and tweak lastIndex.  Since the RegExp may be non-global, we use a
 
24862
                 *  special variant which forces global-like behavior for matching.
 
24863
                 */
 
24864
 
 
24865
                DUK_ASSERT_TOP(ctx, 4);
 
24866
 
 
24867
#ifdef DUK_USE_REGEXP_SUPPORT
 
24868
                if (is_regexp) {
 
24869
                        duk_dup(ctx, 0);
 
24870
                        duk_dup(ctx, 2);
 
24871
                        duk_regexp_match_force_global(thr);  /* [ ... regexp input ] -> [ res_obj ] */
 
24872
                        if (!duk_is_object(ctx, -1)) {
 
24873
                                duk_pop(ctx);
 
24874
                                break;
 
24875
                        }
 
24876
                        matched = 1;
 
24877
 
 
24878
                        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
 
24879
                        DUK_ASSERT(duk_is_number(ctx, -1));
 
24880
                        match_start_coff = duk_get_int(ctx, -1);
 
24881
                        match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
 
24882
                        duk_pop(ctx);
 
24883
 
 
24884
                        if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
 
24885
                                /* don't allow an empty match at the end of the string */
 
24886
                                duk_pop(ctx);
 
24887
                                break;
 
24888
                        }
 
24889
 
 
24890
                        duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
24891
                        DUK_ASSERT(duk_is_number(ctx, -1));
 
24892
                        match_end_coff = duk_get_int(ctx, -1);
 
24893
                        match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
 
24894
                        duk_pop(ctx);
 
24895
 
 
24896
                        /* empty match -> bump and continue */
 
24897
                        if (prev_match_end_boff == match_end_boff) {
 
24898
                                duk_push_int(ctx, match_end_coff + 1);
 
24899
                                duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
24900
                                duk_pop(ctx);
 
24901
                                continue;
 
24902
                        }
 
24903
                } else {
 
24904
#else  /* DUK_USE_REGEXP_SUPPORT */
 
24905
                {  /* unconditionally */
 
24906
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
24907
                        duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
 
24908
                        duk_uint8_t *q_start;               /* match string */
 
24909
                        duk_size_t q_blen, q_clen;
 
24910
 
 
24911
                        p_start = DUK_HSTRING_GET_DATA(h_input);
 
24912
                        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
 
24913
                        p = p_start + prev_match_end_boff;
 
24914
 
 
24915
                        h_sep = duk_get_hstring(ctx, 0);
 
24916
                        DUK_ASSERT(h_sep != NULL);
 
24917
                        q_start = DUK_HSTRING_GET_DATA(h_sep);
 
24918
                        q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
 
24919
                        q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
 
24920
 
 
24921
                        p_end -= q_blen;  /* ensure full memcmp() fits in while */
 
24922
 
 
24923
                        match_start_coff = prev_match_end_coff;
 
24924
 
 
24925
                        if (q_blen == 0) {
 
24926
                                /* Handle empty separator case: it will always match, and always
 
24927
                                 * triggers the check in step 13.c.iii initially.  Note that we
 
24928
                                 * must skip to either end of string or start of first codepoint,
 
24929
                                 * skipping over any continuation bytes!
 
24930
                                 *
 
24931
                                 * Don't allow an empty string to match at the end of the input.
 
24932
                                 */
 
24933
 
 
24934
                                matched = 1;  /* empty separator can always match */
 
24935
 
 
24936
                                match_start_coff++;
 
24937
                                p++;
 
24938
                                while (p < p_end) {
 
24939
                                        if ((p[0] & 0xc0) != 0x80) {
 
24940
                                                goto found;
 
24941
                                        }
 
24942
                                        p++;
 
24943
                                }
 
24944
                                goto not_found;
 
24945
                        }
 
24946
 
 
24947
                        DUK_ASSERT(q_blen > 0 && q_clen > 0);
 
24948
                        while (p <= p_end) {
 
24949
                                DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
 
24950
                                DUK_ASSERT(q_blen > 0);  /* no issues with empty memcmp() */
 
24951
                                if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) {
 
24952
                                        /* never an empty match, so step 13.c.iii can't be triggered */
 
24953
                                        goto found;
 
24954
                                }
 
24955
 
 
24956
                                /* track utf-8 non-continuation bytes */
 
24957
                                if ((p[0] & 0xc0) != 0x80) {
 
24958
                                        match_start_coff++;
 
24959
                                }
 
24960
                                p++;
 
24961
                        }
 
24962
 
 
24963
                 not_found:
 
24964
                        /* not found */
 
24965
                        break;
 
24966
 
 
24967
                 found:
 
24968
                        matched = 1;
 
24969
                        match_start_boff = (duk_uint32_t) (p - p_start);
 
24970
                        match_end_coff = match_start_coff + q_clen;
 
24971
                        match_end_boff = match_start_boff + q_blen;
 
24972
 
 
24973
                        /* empty match (may happen with empty separator) -> bump and continue */
 
24974
                        if (prev_match_end_boff == match_end_boff) {
 
24975
                                prev_match_end_boff++;
 
24976
                                prev_match_end_coff++;
 
24977
                                continue;
 
24978
                        }
 
24979
                }  /* if (is_regexp) */
 
24980
 
 
24981
                /* stack[0] = separator (string or regexp)
 
24982
                 * stack[1] = limit
 
24983
                 * stack[2] = input string
 
24984
                 * stack[3] = result array
 
24985
                 * stack[4] = regexp res_obj (if is_regexp)
 
24986
                 */
 
24987
 
 
24988
                DUK_DDDPRINT("split; match_start b=%d,c=%d, match_end b=%d,c=%d, prev_end b=%d,c=%d",
 
24989
                             (int) match_start_boff, (int) match_start_coff,
 
24990
                             (int) match_end_boff, (int) match_end_coff,
 
24991
                             (int) prev_match_end_boff, (int) prev_match_end_coff);
 
24992
 
 
24993
                duk_push_lstring(ctx,
 
24994
                                 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
 
24995
                                 (size_t) (match_start_boff - prev_match_end_boff));
 
24996
                duk_put_prop_index(ctx, 3, arr_idx);
 
24997
                arr_idx++;
 
24998
                if (arr_idx >= limit) {
 
24999
                        goto hit_limit;
 
25000
                }
 
25001
 
 
25002
#ifdef DUK_USE_REGEXP_SUPPORT
 
25003
                if (is_regexp) {
 
25004
                        duk_size_t i, len;
 
25005
 
 
25006
                        len = duk_get_length(ctx, 4);
 
25007
                        for (i = 1; i < len; i++) {
 
25008
                                duk_get_prop_index(ctx, 4, i);
 
25009
                                duk_put_prop_index(ctx, 3, arr_idx);
 
25010
                                arr_idx++;
 
25011
                                if (arr_idx >= limit) {
 
25012
                                        goto hit_limit;
 
25013
                                }
 
25014
                        }
 
25015
 
 
25016
                        duk_pop(ctx);
 
25017
                        /* lastIndex already set up for next match */
 
25018
                } else {
 
25019
#else  /* DUK_USE_REGEXP_SUPPORT */
 
25020
                {  /* unconditionally */
 
25021
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
25022
                        /* no action */
 
25023
                }
 
25024
 
 
25025
                prev_match_end_boff = match_end_boff;
 
25026
                prev_match_end_coff = match_end_coff;
 
25027
                continue;
 
25028
        }  /* for */
 
25029
 
 
25030
        /* Combined step 11 (empty string special case) and 14-15. */
 
25031
 
 
25032
        DUK_DDDPRINT("split trailer; prev_end b=%d,c=%d",
 
25033
                     (int) prev_match_end_boff, (int) prev_match_end_coff);
 
25034
 
 
25035
        if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
 
25036
                /* Add trailer if:
 
25037
                 *   a) non-empty input
 
25038
                 *   b) empty input and no (zero size) match found (step 11)
 
25039
                 */
 
25040
 
 
25041
                duk_push_lstring(ctx,
 
25042
                                 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
 
25043
                                 (size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
 
25044
                duk_put_prop_index(ctx, 3, arr_idx);
 
25045
                /* No arr_idx update or limit check */
 
25046
        }
 
25047
 
 
25048
        return 1;
 
25049
 
 
25050
 hit_limit:
 
25051
#ifdef DUK_USE_REGEXP_SUPPORT
 
25052
        if (is_regexp) {
 
25053
                duk_pop(ctx);
 
25054
        }
 
25055
#endif
 
25056
 
 
25057
        return 1;
 
25058
}
 
25059
 
 
25060
/*
 
25061
 *  Various
 
25062
 */
 
25063
 
 
25064
#ifdef DUK_USE_REGEXP_SUPPORT
 
25065
static void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, int force_new) {
 
25066
        duk_hthread *thr = (duk_hthread *) ctx;
 
25067
        duk_hobject *h;
 
25068
 
 
25069
        /* Shared helper for match() steps 3-4, search() steps 3-4. */
 
25070
 
 
25071
        DUK_ASSERT(index >= 0);
 
25072
 
 
25073
        if (force_new) {
 
25074
                goto do_new;
 
25075
        }
 
25076
 
 
25077
        h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
 
25078
        if (!h) {
 
25079
                goto do_new;
 
25080
        }
 
25081
        return;
 
25082
 
 
25083
 do_new:
 
25084
        duk_push_hobject(ctx, thr->builtins[DUK_BIDX_REGEXP_CONSTRUCTOR]);
 
25085
        duk_dup(ctx, index);
 
25086
        duk_new(ctx, 1);  /* [ ... RegExp val ] -> [ ... res ] */
 
25087
        duk_replace(ctx, index);
 
25088
}
 
25089
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
25090
 
 
25091
#ifdef DUK_USE_REGEXP_SUPPORT
 
25092
duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
 
25093
        duk_hthread *thr = (duk_hthread *) ctx;
 
25094
 
 
25095
        /* Easiest way to implement the search required by the specification
 
25096
         * is to do a RegExp test() with lastIndex forced to zero.  To avoid
 
25097
         * side effects on the argument, "clone" the RegExp if a RegExp was
 
25098
         * given as input.
 
25099
         *
 
25100
         * The global flag of the RegExp should be ignored; setting lastIndex
 
25101
         * to zero (which happens when "cloning" the RegExp) should have an
 
25102
         * equivalent effect.
 
25103
         */
 
25104
 
 
25105
        DUK_ASSERT_TOP(ctx, 1);
 
25106
        (void) duk_push_this_coercible_to_string(ctx);  /* at index 1 */
 
25107
        duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
 
25108
 
 
25109
        /* stack[0] = regexp
 
25110
         * stack[1] = string
 
25111
         */
 
25112
 
 
25113
        /* Avoid using RegExp.prototype methods, as they're writable and
 
25114
         * configurable and may have been changed.
 
25115
         */
 
25116
 
 
25117
        duk_dup(ctx, 0);
 
25118
        duk_dup(ctx, 1);  /* [ ... re_obj input ] */
 
25119
        duk_regexp_match(thr);  /* -> [ ... res_obj ] */
 
25120
 
 
25121
        if (!duk_is_object(ctx, -1)) {
 
25122
                duk_push_int(ctx, -1);
 
25123
                return 1;
 
25124
        }
 
25125
 
 
25126
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
 
25127
        DUK_ASSERT(duk_is_number(ctx, -1));
 
25128
        return 1;
 
25129
}
 
25130
#else  /* DUK_USE_REGEXP_SUPPORT */
 
25131
duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
 
25132
        DUK_UNREF(ctx);
 
25133
        return DUK_RET_UNSUPPORTED_ERROR;
 
25134
}
 
25135
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
25136
 
 
25137
#ifdef DUK_USE_REGEXP_SUPPORT
 
25138
duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
 
25139
        duk_hthread *thr = (duk_hthread *) ctx;
 
25140
        duk_small_int_t global;
 
25141
        duk_int_t prev_last_index;
 
25142
        duk_int_t this_index;
 
25143
        duk_int_t arr_idx;
 
25144
 
 
25145
        DUK_ASSERT_TOP(ctx, 1);
 
25146
        (void) duk_push_this_coercible_to_string(ctx);
 
25147
        duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
 
25148
        global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
 
25149
        DUK_ASSERT_TOP(ctx, 2);
 
25150
 
 
25151
        /* stack[0] = regexp
 
25152
         * stack[1] = string
 
25153
         */
 
25154
 
 
25155
        if (!global) {
 
25156
                duk_regexp_match(thr);  /* -> [ res_obj ] */
 
25157
                return 1;  /* return 'res_obj' */
 
25158
        }
 
25159
 
 
25160
        /* Global case is more complex. */
 
25161
 
 
25162
        /* [ regexp string ] */
 
25163
 
 
25164
        duk_push_int(ctx, 0);
 
25165
        duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
25166
        duk_push_array(ctx);
 
25167
 
 
25168
        /* [ regexp string res_arr ] */
 
25169
 
 
25170
        prev_last_index = 0;
 
25171
        arr_idx = 0;
 
25172
 
 
25173
        for (;;) {
 
25174
                DUK_ASSERT_TOP(ctx, 3);
 
25175
 
 
25176
                duk_dup(ctx, 0);
 
25177
                duk_dup(ctx, 1);
 
25178
                duk_regexp_match(thr);  /* -> [ ... regexp string ] -> [ ... res_obj ] */
 
25179
 
 
25180
                if (!duk_is_object(ctx, -1)) {
 
25181
                        duk_pop(ctx);
 
25182
                        break;
 
25183
                }
 
25184
 
 
25185
                duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
25186
                DUK_ASSERT(duk_is_number(ctx, -1));
 
25187
                this_index = duk_get_int(ctx, -1);
 
25188
                duk_pop(ctx);
 
25189
 
 
25190
                if (this_index == prev_last_index) {
 
25191
                        this_index++;
 
25192
                        duk_push_int(ctx, this_index);
 
25193
                        duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
 
25194
                }
 
25195
                prev_last_index = this_index;
 
25196
 
 
25197
                duk_get_prop_index(ctx, -1, 0);  /* match string */
 
25198
                duk_put_prop_index(ctx, 2, arr_idx);
 
25199
                arr_idx++;
 
25200
                duk_pop(ctx);  /* res_obj */
 
25201
        }
 
25202
 
 
25203
        if (arr_idx == 0) {
 
25204
                duk_push_null(ctx);
 
25205
        }
 
25206
 
 
25207
        return 1;  /* return 'res_arr' or 'null' */
 
25208
}
 
25209
#else  /* DUK_USE_REGEXP_SUPPORT */
 
25210
duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
 
25211
        DUK_UNREF(ctx);
 
25212
        return DUK_RET_UNSUPPORTED_ERROR;
 
25213
}
 
25214
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
25215
 
 
25216
duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
 
25217
        /* duk_concat() coerces arguments with ToString() in correct order */
 
25218
        (void) duk_push_this_coercible_to_string(ctx);
 
25219
        duk_insert(ctx, 0);  /* this is relatively expensive */
 
25220
        duk_concat(ctx, duk_get_top(ctx));
 
25221
        return 1;
 
25222
}
 
25223
 
 
25224
duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
 
25225
        DUK_ASSERT_TOP(ctx, 0);
 
25226
        (void) duk_push_this_coercible_to_string(ctx);
 
25227
        duk_trim(ctx, 0);
 
25228
        DUK_ASSERT_TOP(ctx, 1);
 
25229
        return 1;
 
25230
}
 
25231
 
 
25232
duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
 
25233
        duk_hstring *h1;
 
25234
        duk_hstring *h2;
 
25235
        duk_size_t h1_len, h2_len, prefix_len;
 
25236
        duk_int_t ret = 0;
 
25237
        int rc;
 
25238
 
 
25239
        /* The current implementation of localeCompare() is simply a codepoint
 
25240
         * by codepoint comparison, implemented with a simple string compare
 
25241
         * because UTF-8 should preserve codepoint ordering (assuming valid
 
25242
         * shortest UTF-8 encoding).
 
25243
         *
 
25244
         * The specification requires that the return value must be related
 
25245
         * to the sort order: e.g. negative means that 'this' comes before
 
25246
         * 'that' in sort order.  We assume an ascending sort order.
 
25247
         */
 
25248
 
 
25249
        /* FIXME: could share code with duk_js_ops.c, duk_js_compare_helper */
 
25250
 
 
25251
        h1 = duk_push_this_coercible_to_string(ctx);
 
25252
        DUK_ASSERT(h1 != NULL);
 
25253
 
 
25254
        h2 = duk_to_hstring(ctx, 0);
 
25255
        DUK_ASSERT(h2 != NULL);
 
25256
 
 
25257
        h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
 
25258
        h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
 
25259
        prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
 
25260
 
 
25261
        /* Zero size compare not an issue with DUK_MEMCMP. */
 
25262
        rc = DUK_MEMCMP((const char *) DUK_HSTRING_GET_DATA(h1),
 
25263
                        (const char *) DUK_HSTRING_GET_DATA(h2),
 
25264
                        prefix_len);
 
25265
 
 
25266
        if (rc < 0) {
 
25267
                ret = -1;
 
25268
                goto done;
 
25269
        } else if (rc > 0) {
 
25270
                ret = 1;
 
25271
                goto done;
 
25272
        }
 
25273
 
 
25274
        /* prefix matches, lengths matter now */
 
25275
        if (h1_len > h2_len) {
 
25276
                ret = 1;
 
25277
                goto done;
 
25278
        } else if (h1_len == h2_len) {
 
25279
                DUK_ASSERT(ret == 0);
 
25280
                goto done;
 
25281
        }
 
25282
        ret = -1;
 
25283
        goto done;
 
25284
 
 
25285
 done:
 
25286
        duk_push_int(ctx, ret);
 
25287
        return 1;
 
25288
}
 
25289
 
 
25290
#line 1 "duk_bi_thread.c"
 
25291
/*
 
25292
 *  Thread builtins
 
25293
 */
 
25294
 
 
25295
/* include removed: duk_internal.h */
 
25296
 
 
25297
/*
 
25298
 *  Constructor
 
25299
 */
 
25300
 
 
25301
duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
 
25302
        duk_hthread *new_thr;
 
25303
        duk_hobject *func;
 
25304
 
 
25305
        if (!duk_is_callable(ctx, 0)) {
 
25306
                return DUK_RET_TYPE_ERROR;
 
25307
        }
 
25308
        func = duk_get_hobject(ctx, 0);
 
25309
        DUK_ASSERT(func != NULL);
 
25310
 
 
25311
        duk_push_thread(ctx);
 
25312
        new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
 
25313
        DUK_ASSERT(new_thr != NULL);
 
25314
        new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
 
25315
 
 
25316
        /* push initial function call to new thread stack; this is
 
25317
         * picked up by resume().
 
25318
         */
 
25319
        duk_push_hobject((duk_context *) new_thr, func);
 
25320
 
 
25321
        return 1;  /* return thread */
 
25322
}
 
25323
 
 
25324
/*
 
25325
 *  Resume a thread.
 
25326
 *
 
25327
 *  The thread must be in resumable state, either (a) new thread which hasn't
 
25328
 *  yet started, or (b) a thread which has previously yielded.  This method
 
25329
 *  must be called from an Ecmascript function.
 
25330
 *
 
25331
 *  Args:
 
25332
 *    - thread
 
25333
 *    - value
 
25334
 *    - isError (defaults to false)
 
25335
 *
 
25336
 *  Note: yield and resume handling is currently asymmetric.
 
25337
 */
 
25338
 
 
25339
duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
 
25340
        duk_hthread *thr = (duk_hthread *) ctx;
 
25341
        duk_hthread *thr_resume;
 
25342
        duk_tval tv_tmp;
 
25343
        duk_tval *tv;
 
25344
        duk_hobject *func;
 
25345
        duk_small_int_t is_error;
 
25346
 
 
25347
        DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
 
25348
                     duk_get_tval(ctx, 0),
 
25349
                     duk_get_tval(ctx, 1),
 
25350
                     duk_get_tval(ctx, 2));
 
25351
 
 
25352
        DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
 
25353
        DUK_ASSERT(thr->heap->curr_thread == thr);
 
25354
 
 
25355
        thr_resume = duk_require_hthread(ctx, 0);
 
25356
        is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
 
25357
        duk_set_top(ctx, 2);
 
25358
 
 
25359
        /* [ thread value ] */
 
25360
 
 
25361
        /*
 
25362
         *  Thread state and calling context checks
 
25363
         */
 
25364
 
 
25365
        if (thr->callstack_top < 2) {
 
25366
                DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)");
 
25367
                goto state_error;
 
25368
        }
 
25369
        DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL);  /* us */
 
25370
        DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func));
 
25371
        DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL);  /* caller */
 
25372
 
 
25373
        if (!DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func)) {
 
25374
                DUK_DDPRINT("resume state invalid: caller must be Ecmascript code");
 
25375
                goto state_error;
 
25376
        }
 
25377
 
 
25378
        /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
 
25379
         * like for yield.
 
25380
         */
 
25381
 
 
25382
        if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
 
25383
            thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
 
25384
                DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED");
 
25385
                goto state_error;
 
25386
        }
 
25387
 
 
25388
        DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
 
25389
                   thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
 
25390
 
 
25391
        /* Further state-dependent pre-checks */
 
25392
 
 
25393
        if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
 
25394
                /* no pre-checks now, assume a previous yield() has left things in
 
25395
                 * tip-top shape (longjmp handler will assert for these).
 
25396
                 */
 
25397
        } else {
 
25398
                DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
 
25399
 
 
25400
                if ((thr_resume->callstack_top != 0) ||
 
25401
                    (thr_resume->valstack_top - thr_resume->valstack != 1)) {
 
25402
                        goto state_invalid_initial;
 
25403
                }
 
25404
                tv = &thr_resume->valstack_top[-1];
 
25405
                DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
 
25406
                if (!DUK_TVAL_IS_OBJECT(tv)) {
 
25407
                        goto state_invalid_initial;
 
25408
                }
 
25409
                func = DUK_TVAL_GET_OBJECT(tv);
 
25410
                DUK_ASSERT(func != NULL);
 
25411
                if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
25412
                        /* Note: cannot be a bound function either right now,
 
25413
                         * this would be easy to relax though.
 
25414
                         */
 
25415
                        goto state_invalid_initial;
 
25416
                }
 
25417
 
 
25418
        }
 
25419
 
 
25420
        /*
 
25421
         *  The error object has been augmented with a traceback and other
 
25422
         *  info from its creation point -- usually another thread.  The
 
25423
         *  error handler is called here right before throwing, but it also
 
25424
         *  runs in the resumer's thread.  It might be nice to get a traceback
 
25425
         *  from the resumee but this is not the case now.
 
25426
         */
 
25427
 
 
25428
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
25429
        if (is_error) {
 
25430
                DUK_ASSERT_TOP(ctx, 2);  /* value (error) is at stack top */
 
25431
                duk_err_augment_error_throw(thr);  /* in resumer's context */
 
25432
        }
 
25433
#endif
 
25434
 
 
25435
#ifdef DUK_USE_DEBUG  /* debug logging */
 
25436
        if (is_error) {
 
25437
                DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
 
25438
                             duk_get_tval(ctx, 0),
 
25439
                             duk_get_tval(ctx, 1));
 
25440
        } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
 
25441
                DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
 
25442
                             duk_get_tval(ctx, 0),
 
25443
                             duk_get_tval(ctx, 1));
 
25444
        } else {
 
25445
                DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
 
25446
                             duk_get_tval(ctx, 0),
 
25447
                             duk_get_tval(ctx, 1));
 
25448
        }
 
25449
#endif
 
25450
 
 
25451
        thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
 
25452
 
 
25453
        /* lj value2: thread */
 
25454
        DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
 
25455
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value2);
 
25456
        DUK_TVAL_SET_TVAL(&thr->heap->lj.value2, &thr->valstack_bottom[0]);
 
25457
        DUK_TVAL_INCREF(thr, &thr->heap->lj.value2);
 
25458
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
25459
 
 
25460
        /* lj value1: value */
 
25461
        DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
 
25462
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
25463
        DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, &thr->valstack_bottom[1]);
 
25464
        DUK_TVAL_INCREF(thr, &thr->heap->lj.value1);
 
25465
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
25466
 
 
25467
        thr->heap->lj.iserror = is_error;
 
25468
 
 
25469
        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
 
25470
        duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
 
25471
        return 0;  /* never here */
 
25472
 
 
25473
 state_invalid_initial:
 
25474
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid initial thread state/stack");
 
25475
        return 0;  /* never here */
 
25476
 
 
25477
 state_error:
 
25478
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid state for resume");
 
25479
        return 0;  /* never here */
 
25480
}
 
25481
 
 
25482
/*
 
25483
 *  Yield the current thread.
 
25484
 *
 
25485
 *  The thread must be in yieldable state: it must have a resumer, and there
 
25486
 *  must not be any yield-preventing calls (native calls and constructor calls,
 
25487
 *  currently) in the thread's call stack (otherwise a resume would not be
 
25488
 *  possible later).  This method must be called from an Ecmascript function.
 
25489
 *
 
25490
 *  Args:
 
25491
 *    - value
 
25492
 *    - isError (defaults to false)
 
25493
 *
 
25494
 *  Note: yield and resume handling is currently asymmetric.
 
25495
 */
 
25496
 
 
25497
duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
 
25498
        duk_hthread *thr = (duk_hthread *) ctx;
 
25499
        duk_tval tv_tmp;
 
25500
        duk_small_int_t is_error;
 
25501
 
 
25502
        DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
 
25503
                     duk_get_tval(ctx, 0),
 
25504
                     duk_get_tval(ctx, 1));
 
25505
 
 
25506
        DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
 
25507
        DUK_ASSERT(thr->heap->curr_thread == thr);
 
25508
 
 
25509
        is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
 
25510
        duk_set_top(ctx, 1);
 
25511
 
 
25512
        /* [ value ] */
 
25513
 
 
25514
        /*
 
25515
         *  Thread state and calling context checks
 
25516
         */
 
25517
 
 
25518
        if (!thr->resumer) {
 
25519
                DUK_DDPRINT("yield state invalid: current thread must have a resumer");
 
25520
                goto state_error;
 
25521
        }
 
25522
        DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
 
25523
 
 
25524
        if (thr->callstack_top < 2) {
 
25525
                DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)");
 
25526
                goto state_error;
 
25527
        }
 
25528
        DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL);  /* us */
 
25529
        DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func));
 
25530
        DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL);  /* caller */
 
25531
 
 
25532
        if (!DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func)) {
 
25533
                DUK_DDPRINT("yield state invalid: caller must be Ecmascript code");
 
25534
                goto state_error;
 
25535
        }
 
25536
 
 
25537
        DUK_ASSERT(thr->callstack_preventcount >= 1);  /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
 
25538
        if (thr->callstack_preventcount != 1) {
 
25539
                /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
 
25540
                DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %d)",
 
25541
                            (int) thr->callstack_preventcount);
 
25542
                goto state_error;
 
25543
        }
 
25544
 
 
25545
        /*
 
25546
         *  The error object has been augmented with a traceback and other
 
25547
         *  info from its creation point -- usually the current thread.
 
25548
         *  The error handler, however, is called right before throwing
 
25549
         *  and runs in the yielder's thread.
 
25550
         */
 
25551
 
 
25552
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
25553
        if (is_error) {
 
25554
                DUK_ASSERT_TOP(ctx, 1);  /* value (error) is at stack top */
 
25555
                duk_err_augment_error_throw(thr);  /* in yielder's context */
 
25556
        }
 
25557
#endif
 
25558
 
 
25559
#ifdef DUK_USE_DEBUG
 
25560
        if (is_error) {
 
25561
                DUK_DDDPRINT("YIELD ERROR: value=%!T",
 
25562
                             duk_get_tval(ctx, 0));
 
25563
        } else {
 
25564
                DUK_DDDPRINT("YIELD NORMAL: value=%!T",
 
25565
                             duk_get_tval(ctx, 0));
 
25566
        }
 
25567
#endif
 
25568
 
 
25569
        /*
 
25570
         *  Process yield
 
25571
         *
 
25572
         *  After longjmp(), processing continues in bytecode executor longjmp
 
25573
         *  handler, which will e.g. update thr->resumer to NULL.
 
25574
         */
 
25575
 
 
25576
        thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
 
25577
 
 
25578
        /* lj value1: value */
 
25579
        DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
 
25580
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
25581
        DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, &thr->valstack_bottom[0]);
 
25582
        DUK_TVAL_INCREF(thr, &thr->heap->lj.value1);
 
25583
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
25584
 
 
25585
        thr->heap->lj.iserror = is_error;
 
25586
 
 
25587
        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
 
25588
        duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
 
25589
        return 0;  /* never here */
 
25590
 
 
25591
 state_error:
 
25592
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid state for yield");
 
25593
        return 0;  /* never here */
 
25594
}
 
25595
 
 
25596
duk_ret_t duk_bi_thread_current(duk_context *ctx) {
 
25597
        duk_push_current_thread(ctx);
 
25598
        return 1;
 
25599
}
 
25600
 
 
25601
#line 1 "duk_bi_thrower.c"
 
25602
/*
 
25603
 *  Type error thrower, E5 Section 13.2.3.
 
25604
 */
 
25605
 
 
25606
/* include removed: duk_internal.h */
 
25607
 
 
25608
int duk_bi_type_error_thrower(duk_context *ctx) {
 
25609
        DUK_UNREF(ctx);
 
25610
        return DUK_RET_TYPE_ERROR;
 
25611
}
 
25612
#line 1 "duk_builtins.c"
 
25613
/*
 
25614
 *  Automatically generated by genbuiltins.py, do not edit!
 
25615
 */
 
25616
 
 
25617
/* include removed: duk_internal.h */
 
25618
 
 
25619
#if defined(DUK_USE_DOUBLE_LE)
 
25620
const duk_uint8_t duk_strings_data[] = {
 
25621
55,86,227,24,145,55,102,120,144,3,63,94,228,54,100,137,186,26,20,164,137,
 
25622
186,50,11,164,109,77,215,5,61,35,106,3,25,110,8,22,158,130,38,163,8,217,
 
25623
200,158,76,156,210,117,128,153,203,210,70,46,137,187,18,27,164,187,201,209,
 
25624
130,100,55,91,70,4,145,63,66,231,44,128,105,187,41,197,13,49,122,8,196,24,
 
25625
71,75,70,138,104,115,77,215,5,36,20,217,255,122,45,26,47,186,156,104,79,
 
25626
253,119,253,253,22,139,70,139,232,190,234,113,161,63,245,223,247,244,90,
 
25627
106,26,95,162,251,169,198,132,255,214,255,223,209,105,13,47,209,125,212,
 
25628
227,66,127,235,127,239,232,180,208,55,232,190,234,113,161,63,245,255,247,
 
25629
244,90,163,70,66,253,23,221,78,52,39,254,174,110,234,220,110,202,113,67,76,
 
25630
65,45,198,10,194,210,148,19,2,202,72,197,209,37,129,22,148,100,13,12,89,
 
25631
196,2,32,226,11,12,172,153,197,72,196,141,153,162,73,81,132,56,156,199,128,
 
25632
83,42,100,230,136,169,147,155,115,4,18,39,219,125,160,206,75,140,100,16,
 
25633
200,209,12,168,104,140,33,128,83,34,208,210,17,13,43,143,82,70,72,115,70,
 
25634
70,213,4,140,102,120,186,201,36,98,40,144,19,33,196,230,61,11,34,55,18,24,
 
25635
32,145,15,185,158,36,0,213,178,161,160,90,50,72,159,98,2,214,66,19,108,3,
 
25636
203,176,68,210,46,230,116,73,27,120,190,201,104,105,15,185,58,145,17,15,
 
25637
186,130,36,109,79,181,146,228,109,79,186,130,44,3,209,178,186,44,2,228,157,
 
25638
135,19,32,156,50,23,109,37,230,125,204,17,49,38,109,212,11,161,14,247,33,
 
25639
179,36,76,26,20,164,138,103,16,8,131,4,192,165,161,164,235,104,192,146,40,
 
25640
42,22,78,180,12,32,158,34,202,96,18,157,217,158,46,183,103,135,147,164,140,
 
25641
93,19,244,116,84,192,242,24,64,90,200,70,117,13,168,22,129,253,7,70,9,144,
 
25642
191,183,245,223,93,245,223,186,47,138,248,144,253,0,126,176,95,91,246,2,
 
25643
250,191,176,15,216,39,235,122,134,149,13,68,240,159,171,234,26,84,53,19,
 
25644
194,58,134,149,13,68,240,103,5,36,20,205,41,197,13,49,155,70,4,145,56,92,
 
25645
229,144,13,77,26,50,21,13,32,211,41,197,13,50,11,129,204,13,36,161,25,142,
 
25646
72,105,98,234,52,102,136,26,55,48,111,117,134,196,52,108,5,198,183,24,165,
 
25647
91,157,17,146,239,24,157,34,8,136,89,65,48,55,236,136,9,129,164,4,144,210,
 
25648
0,78,144,192,25,23,210,132,103,246,71,244,161,25,253,142,190,200,94,122,13,
 
25649
229,184,223,99,246,4,47,150,227,125,145,7,229,183,236,137,229,183,236,126,
 
25650
192,61,33,216,73,72,6,33,26,6,16,168,107,233,50,161,163,37,201,245,31,127,
 
25651
247,95,82,149,130,83,234,26,50,93,44,162,230,133,161,164,82,12,215,68,157,
 
25652
16,36,67,73,212,136,136,73,146,83,33,46,65,46,110,241,153,57,122,113,67,76,
 
25653
121,18,125,193,1,19,152,147,238,8,8,154,110,242,100,230,174,110,242,36,233,
 
25654
122,113,67,76,185,187,212,152,165,233,197,13,51,164,73,250,147,17,125,69,
 
25655
175,184,32,34,185,18,125,45,22,190,224,128,138,228,73,250,147,19,60,230,
 
25656
204,232,145,39,214,57,179,58,164,73,250,147,16,252,9,144,242,36,250,48,76,
 
25657
139,145,39,234,76,71,243,169,25,34,68,159,78,234,70,77,145,39,234,76,76,
 
25658
242,27,73,146,74,145,39,214,33,180,153,36,217,18,126,164,197,47,16,78,104,
 
25659
228,169,18,125,145,4,230,142,82,145,39,234,76,76,242,22,180,72,130,115,71,
 
25660
39,200,147,235,16,181,162,68,19,154,57,30,68,159,102,134,18,38,36,251,52,
 
25661
48,153,115,73,215,20,178,36,228,98,79,212,152,153,228,45,104,145,4,230,142,
 
25662
79,49,39,214,33,107,68,136,39,52,114,105,137,63,82,98,151,136,39,52,114,81,
 
25663
137,62,200,130,115,71,38,152,147,245,38,38,121,13,164,201,37,24,147,235,16,
 
25664
218,76,146,89,137,63,82,98,63,157,72,201,6,36,250,119,82,50,73,137,63,82,
 
25665
98,31,129,131,24,147,232,193,133,24,147,245,38,33,248,19,33,204,73,244,96,
 
25666
153,22,98,79,212,152,153,231,54,103,65,137,62,177,205,153,220,98,79,212,
 
25667
152,139,234,45,125,193,1,21,152,147,233,104,181,247,4,4,78,98,79,179,67,9,
 
25668
41,187,171,112,128,178,118,104,97,59,41,197,13,52,166,238,173,194,2,201,
 
25669
209,130,100,236,167,20,52,204,155,187,52,48,157,148,226,134,153,147,119,70,
 
25670
9,147,178,156,80,211,13,174,176,253,73,136,175,4,100,69,205,221,124,72,36,
 
25671
73,14,107,102,238,146,239,115,72,217,160,11,60,221,210,162,228,28,124,247,
 
25672
73,19,69,73,164,52,168,106,39,136,249,164,48,38,138,147,72,105,80,212,79,3,
 
25673
235,65,214,167,204,67,117,80,46,132,79,152,11,234,160,93,8,105,80,50,156,
 
25674
73,56,161,145,155,186,183,8,11,39,104,247,146,61,16,36,69,205,221,163,222,
 
25675
72,244,64,145,35,55,117,110,16,22,78,173,214,36,122,32,72,139,155,186,183,
 
25676
88,145,232,129,34,38,84,12,167,20,52,197,147,214,137,154,68,4,68,115,196,
 
25677
143,88,4,66,176,19,17,218,183,8,11,39,68,230,60,17,34,132,112,71,162,112,
 
25678
201,208,76,194,56,35,208,77,133,139,153,209,28,17,232,156,50,46,36,29,4,78,
 
25679
197,6,60,205,18,14,130,33,138,133,204,145,27,0,243,149,209,233,0,35,146,78,
 
25680
97,10,74,146,56,90,193,41,245,13,25,47,215,20,232,104,201,126,184,167,163,
 
25681
100,116,22,102,147,214,129,16,146,116,102,89,45,2,33,100,116,22,103,137,42,
 
25682
72,200,132,125,36,113,189,207,34,92,134,152,78,104,129,51,162,93,4,98,12,
 
25683
36,17,53,24,70,206,70,16,22,178,68,129,67,70,65,1,107,40,30,245,226,143,
 
25684
139,158,72,207,29,68,186,70,209,132,136,2,178,53,18,235,226,233,186,120,
 
25685
121,58,226,184,224,151,93,102,245,241,115,201,25,224,245,2,232,78,184,174,
 
25686
155,186,183,8,11,39,101,56,161,166,68,221,217,78,40,105,150,39,54,83,141,5,
 
25687
55,68,114,36,198,98,77,68,109,24,72,128,43,35,4,230,149,6,164,64,21,145,22,
 
25688
138,38,0,172,133,168,23,66,17,68,196,152,137,116,151,153,27,36,5,100,66,37,
 
25689
210,197,217,35,80,137,118,68,2,200,56,190,36,169,27,62,146,243,35,100,135,
 
25690
54,70,44,72,76,144,146,32,23,1,144,168,105,58,248,185,228,140,208,73,56,
 
25691
100,42,26,78,190,46,121,35,60,24,81,32,38,73,152,147,235,172,222,190,46,
 
25692
121,35,60,117,160,97,37,131,18,125,117,155,215,197,207,36,103,142,140,146,
 
25693
20,80,249,186,46,49,39,215,197,211,116,240,242,117,197,75,226,233,186,120,
 
25694
121,12,178,52,211,57,64,178,70,101,124,80,217,162,141,36,132,7,144,196,144,
 
25695
128,242,72,141,19,134,79,82,40,23,156,199,185,164,108,210,70,137,195,39,
 
25696
169,20,72,100,19,134,79,82,40,23,156,199,185,164,108,210,50,9,195,39,169,
 
25697
20,33,18,233,80,212,76,133,68,186,208,117,170,120,35,34,116,171,112,38,135,
 
25698
130,50,39,80,217,144,149,2,209,234,69,4,244,98,232,167,179,195,201,210,70,
 
25699
46,138,251,44,54,96,191,73,24,186,46,236,72,82,68,141,17,58,72,197,209,87,
 
25700
98,6,152,157,36,98,232,167,164,168,23,210,70,46,137,67,18,1,68,16,36,66,
 
25701
136,19,17,208,39,54,104,109,8,129,144,52,49,137,19,140,133,5,23,51,12,139,
 
25702
36,200,33,184,132,92,136,114,161,160,90,240,50,186,40,45,26,41,161,205,18,
 
25703
10,36,53,72,108,166,6,136,142,40,218,75,26,36,157,34,211,74,200,152,142,73,
 
25704
157,18,44,207,23,88,115,142,13,60,60,142,40,234,8,146,174,64,203,99,161,
 
25705
100,37,145,51,148,75,4,164,81,57,178,153,8,218,48,196,187,221,25,156,151,
 
25706
153,26,57,25,12,123,163,50,202,143,36,72,218,45,100,156,104,66,148,11,145,
 
25707
20,134,61,100,97,27,57,37,13,153,34,80,8,131,89,38,119,128,74,1,136,119,
 
25708
197,21,4,200,151,197,211,32,166,65,153,244,10,208,35,74,96,154,4,92,32,139,
 
25709
24,
 
25710
};
 
25711
 
 
25712
/* to convert a heap stridx to a token number, subtract
 
25713
 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
 
25714
 */
 
25715
 
 
25716
/* native functions: 128 */
 
25717
const duk_c_function duk_bi_native_functions[] = {
 
25718
        (duk_c_function) duk_bi_array_constructor,
 
25719
        (duk_c_function) duk_bi_array_constructor_is_array,
 
25720
        (duk_c_function) duk_bi_array_prototype_concat,
 
25721
        (duk_c_function) duk_bi_array_prototype_indexof_shared,
 
25722
        (duk_c_function) duk_bi_array_prototype_iter_shared,
 
25723
        (duk_c_function) duk_bi_array_prototype_join_shared,
 
25724
        (duk_c_function) duk_bi_array_prototype_pop,
 
25725
        (duk_c_function) duk_bi_array_prototype_push,
 
25726
        (duk_c_function) duk_bi_array_prototype_reduce_shared,
 
25727
        (duk_c_function) duk_bi_array_prototype_reverse,
 
25728
        (duk_c_function) duk_bi_array_prototype_shift,
 
25729
        (duk_c_function) duk_bi_array_prototype_slice,
 
25730
        (duk_c_function) duk_bi_array_prototype_sort,
 
25731
        (duk_c_function) duk_bi_array_prototype_splice,
 
25732
        (duk_c_function) duk_bi_array_prototype_to_string,
 
25733
        (duk_c_function) duk_bi_array_prototype_unshift,
 
25734
        (duk_c_function) duk_bi_boolean_constructor,
 
25735
        (duk_c_function) duk_bi_boolean_prototype_tostring_shared,
 
25736
        (duk_c_function) duk_bi_buffer_constructor,
 
25737
        (duk_c_function) duk_bi_buffer_prototype_tostring_shared,
 
25738
        (duk_c_function) duk_bi_date_constructor,
 
25739
        (duk_c_function) duk_bi_date_constructor_now,
 
25740
        (duk_c_function) duk_bi_date_constructor_parse,
 
25741
        (duk_c_function) duk_bi_date_constructor_utc,
 
25742
        (duk_c_function) duk_bi_date_prototype_get_shared,
 
25743
        (duk_c_function) duk_bi_date_prototype_get_timezone_offset,
 
25744
        (duk_c_function) duk_bi_date_prototype_set_shared,
 
25745
        (duk_c_function) duk_bi_date_prototype_set_time,
 
25746
        (duk_c_function) duk_bi_date_prototype_to_json,
 
25747
        (duk_c_function) duk_bi_date_prototype_tostring_shared,
 
25748
        (duk_c_function) duk_bi_date_prototype_value_of,
 
25749
        (duk_c_function) duk_bi_duktape_object_act,
 
25750
        (duk_c_function) duk_bi_duktape_object_compact,
 
25751
        (duk_c_function) duk_bi_duktape_object_dec,
 
25752
        (duk_c_function) duk_bi_duktape_object_enc,
 
25753
        (duk_c_function) duk_bi_duktape_object_fin,
 
25754
        (duk_c_function) duk_bi_duktape_object_gc,
 
25755
        (duk_c_function) duk_bi_duktape_object_info,
 
25756
        (duk_c_function) duk_bi_duktape_object_line,
 
25757
        (duk_c_function) duk_bi_error_constructor_shared,
 
25758
        (duk_c_function) duk_bi_error_prototype_filename_getter,
 
25759
        (duk_c_function) duk_bi_error_prototype_linenumber_getter,
 
25760
        (duk_c_function) duk_bi_error_prototype_nop_setter,
 
25761
        (duk_c_function) duk_bi_error_prototype_stack_getter,
 
25762
        (duk_c_function) duk_bi_error_prototype_to_string,
 
25763
        (duk_c_function) duk_bi_function_constructor,
 
25764
        (duk_c_function) duk_bi_function_prototype,
 
25765
        (duk_c_function) duk_bi_function_prototype_apply,
 
25766
        (duk_c_function) duk_bi_function_prototype_bind,
 
25767
        (duk_c_function) duk_bi_function_prototype_call,
 
25768
        (duk_c_function) duk_bi_function_prototype_to_string,
 
25769
        (duk_c_function) duk_bi_global_object_alert,
 
25770
        (duk_c_function) duk_bi_global_object_decode_uri,
 
25771
        (duk_c_function) duk_bi_global_object_decode_uri_component,
 
25772
        (duk_c_function) duk_bi_global_object_encode_uri,
 
25773
        (duk_c_function) duk_bi_global_object_encode_uri_component,
 
25774
        (duk_c_function) duk_bi_global_object_escape,
 
25775
        (duk_c_function) duk_bi_global_object_eval,
 
25776
        (duk_c_function) duk_bi_global_object_is_finite,
 
25777
        (duk_c_function) duk_bi_global_object_is_nan,
 
25778
        (duk_c_function) duk_bi_global_object_parse_float,
 
25779
        (duk_c_function) duk_bi_global_object_parse_int,
 
25780
        (duk_c_function) duk_bi_global_object_print,
 
25781
        (duk_c_function) duk_bi_global_object_unescape,
 
25782
        (duk_c_function) duk_bi_json_object_parse,
 
25783
        (duk_c_function) duk_bi_json_object_stringify,
 
25784
        (duk_c_function) duk_bi_logger_constructor,
 
25785
        (duk_c_function) duk_bi_logger_prototype_fmt,
 
25786
        (duk_c_function) duk_bi_logger_prototype_log_shared,
 
25787
        (duk_c_function) duk_bi_logger_prototype_raw,
 
25788
        (duk_c_function) duk_bi_math_object_max,
 
25789
        (duk_c_function) duk_bi_math_object_min,
 
25790
        (duk_c_function) duk_bi_math_object_onearg_shared,
 
25791
        (duk_c_function) duk_bi_math_object_random,
 
25792
        (duk_c_function) duk_bi_math_object_twoarg_shared,
 
25793
        (duk_c_function) duk_bi_number_constructor,
 
25794
        (duk_c_function) duk_bi_number_prototype_to_exponential,
 
25795
        (duk_c_function) duk_bi_number_prototype_to_fixed,
 
25796
        (duk_c_function) duk_bi_number_prototype_to_locale_string,
 
25797
        (duk_c_function) duk_bi_number_prototype_to_precision,
 
25798
        (duk_c_function) duk_bi_number_prototype_to_string,
 
25799
        (duk_c_function) duk_bi_number_prototype_value_of,
 
25800
        (duk_c_function) duk_bi_object_constructor,
 
25801
        (duk_c_function) duk_bi_object_constructor_create,
 
25802
        (duk_c_function) duk_bi_object_constructor_define_properties,
 
25803
        (duk_c_function) duk_bi_object_constructor_define_property,
 
25804
        (duk_c_function) duk_bi_object_constructor_get_own_property_descriptor,
 
25805
        (duk_c_function) duk_bi_object_constructor_get_own_property_names,
 
25806
        (duk_c_function) duk_bi_object_constructor_get_prototype_of,
 
25807
        (duk_c_function) duk_bi_object_constructor_is_extensible,
 
25808
        (duk_c_function) duk_bi_object_constructor_is_sealed_frozen_shared,
 
25809
        (duk_c_function) duk_bi_object_constructor_keys,
 
25810
        (duk_c_function) duk_bi_object_constructor_prevent_extensions,
 
25811
        (duk_c_function) duk_bi_object_constructor_seal_freeze_shared,
 
25812
        (duk_c_function) duk_bi_object_prototype_has_own_property,
 
25813
        (duk_c_function) duk_bi_object_prototype_is_prototype_of,
 
25814
        (duk_c_function) duk_bi_object_prototype_property_is_enumerable,
 
25815
        (duk_c_function) duk_bi_object_prototype_to_locale_string,
 
25816
        (duk_c_function) duk_bi_object_prototype_to_string,
 
25817
        (duk_c_function) duk_bi_object_prototype_value_of,
 
25818
        (duk_c_function) duk_bi_pointer_constructor,
 
25819
        (duk_c_function) duk_bi_pointer_prototype_tostring_shared,
 
25820
        (duk_c_function) duk_bi_regexp_constructor,
 
25821
        (duk_c_function) duk_bi_regexp_prototype_exec,
 
25822
        (duk_c_function) duk_bi_regexp_prototype_test,
 
25823
        (duk_c_function) duk_bi_regexp_prototype_to_string,
 
25824
        (duk_c_function) duk_bi_string_constructor,
 
25825
        (duk_c_function) duk_bi_string_constructor_from_char_code,
 
25826
        (duk_c_function) duk_bi_string_prototype_caseconv_shared,
 
25827
        (duk_c_function) duk_bi_string_prototype_char_at,
 
25828
        (duk_c_function) duk_bi_string_prototype_char_code_at,
 
25829
        (duk_c_function) duk_bi_string_prototype_concat,
 
25830
        (duk_c_function) duk_bi_string_prototype_indexof_shared,
 
25831
        (duk_c_function) duk_bi_string_prototype_locale_compare,
 
25832
        (duk_c_function) duk_bi_string_prototype_match,
 
25833
        (duk_c_function) duk_bi_string_prototype_replace,
 
25834
        (duk_c_function) duk_bi_string_prototype_search,
 
25835
        (duk_c_function) duk_bi_string_prototype_slice,
 
25836
        (duk_c_function) duk_bi_string_prototype_split,
 
25837
        (duk_c_function) duk_bi_string_prototype_substr,
 
25838
        (duk_c_function) duk_bi_string_prototype_substring,
 
25839
        (duk_c_function) duk_bi_string_prototype_to_string,
 
25840
        (duk_c_function) duk_bi_string_prototype_trim,
 
25841
        (duk_c_function) duk_bi_thread_constructor,
 
25842
        (duk_c_function) duk_bi_thread_current,
 
25843
        (duk_c_function) duk_bi_thread_resume,
 
25844
        (duk_c_function) duk_bi_thread_yield,
 
25845
        (duk_c_function) duk_bi_type_error_thrower,
 
25846
};
 
25847
 
 
25848
const duk_uint8_t duk_builtins_data[] = {
 
25849
105,195,74,144,77,40,105,45,9,124,104,46,3,3,72,0,71,225,65,165,168,33,243,
 
25850
6,145,0,122,24,210,150,14,249,35,120,160,55,226,13,76,192,196,177,164,156,
 
25851
22,192,4,202,52,147,197,88,0,169,70,146,120,163,0,23,40,210,79,19,96,3,37,
 
25852
26,73,226,76,0,108,163,73,60,69,128,14,148,105,39,136,48,1,242,144,56,208,
 
25853
254,80,10,26,94,192,63,72,105,18,1,253,1,165,144,5,244,70,148,32,7,202,20,
 
25854
31,255,170,188,128,0,0,0,0,0,1,240,254,93,128,0,0,0,0,0,1,224,254,98,136,
 
25855
19,48,130,70,32,68,198,8,25,0,243,40,28,102,3,76,224,97,160,11,52,162,166,
 
25856
164,80,214,137,155,17,35,106,34,110,68,13,224,81,192,9,56,74,39,25,176,243,
 
25857
146,67,143,81,13,60,36,48,236,144,179,162,66,141,9,9,53,36,32,216,144,115,
 
25858
114,65,142,9,5,63,36,16,248,122,6,102,61,255,255,130,71,134,0,2,135,248,6,
 
25859
192,22,8,255,86,67,249,92,143,213,52,63,21,88,251,84,67,233,116,143,149,
 
25860
210,128,0,190,23,8,247,90,35,217,104,160,0,47,85,146,61,22,201,255,225,0,
 
25861
51,177,136,14,182,16,58,152,192,233,94,35,161,124,142,118,2,10,47,224,0,31,
 
25862
226,0,35,176,200,14,98,244,57,76,79,156,134,7,194,143,248,0,184,64,72,31,
 
25863
227,0,171,176,56,14,176,80,128,0,184,0,143,155,224,164,111,3,1,186,14,124,
 
25864
220,9,3,108,40,13,160,180,54,67,8,216,13,94,107,135,159,53,128,207,192,0,
 
25865
90,160,103,255,255,237,64,67,70,152,33,168,0,11,72,16,212,0,9,162,8,106,0,
 
25866
6,208,4,53,0,4,103,132,31,128,0,179,130,15,255,255,197,39,240,1,102,181,
 
25867
159,7,249,0,146,33,1,148,118,60,129,212,242,6,99,105,25,109,196,112,55,159,
 
25868
53,156,13,26,174,6,160,0,44,167,18,50,92,136,200,115,67,29,208,141,167,84,
 
25869
49,157,144,197,120,67,17,176,12,54,192,48,155,2,0,2,193,108,8,0,11,1,232,
 
25870
11,247,116,10,95,224,0,31,229,2,72,140,19,176,68,32,0,46,161,16,10,111,226,
 
25871
175,160,127,255,255,255,255,255,247,191,175,96,0,128,0,0,0,0,0,0,47,32,0,0,
 
25872
0,0,0,0,124,63,174,160,0,0,0,0,0,0,120,63,174,224,0,0,0,0,0,0,120,127,128,
 
25873
31,230,2,72,128,0,0,0,0,0,0,0,0,51,177,64,142,180,226,58,148,64,185,77,34,
 
25874
225,48,139,116,242,10,127,224,6,182,22,34,212,95,249,104,42,0,255,56,18,68,
 
25875
128,0,0,0,0,0,15,135,251,93,131,161,0,104,89,142,132,0,161,100,58,16,4,135,
 
25876
88,232,64,58,22,35,161,0,168,88,14,132,3,33,28,58,16,6,4,104,232,65,24,145,
 
25877
131,132,117,15,1,94,60,5,112,192,64,2,21,163,0,86,12,4,64,33,86,48,17,0,5,
 
25878
80,192,72,3,21,35,1,32,4,84,12,5,192,33,78,48,23,0,5,48,192,76,2,20,163,1,
 
25879
48,0,82,12,5,0,33,70,48,20,0,5,16,192,84,2,20,35,1,80,0,80,12,5,128,33,62,
 
25880
48,22,0,4,240,200,19,163,100,78,13,20,68,33,54,52,81,16,4,208,210,249,8,66,
 
25881
100,105,124,132,1,48,52,254,98,16,151,26,127,49,0,75,13,79,160,132,37,70,
 
25882
167,208,64,18,131,69,16,8,73,141,20,64,1,36,52,190,64,16,145,26,95,32,0,72,
 
25883
13,63,152,4,163,198,159,204,0,81,99,1,0,24,69,13,20,200,4,84,127,0,0,255,
 
25884
64,98,44,16,48,0,128,161,161,32,128,241,144,177,144,145,144,114,0,0,0,0,0,
 
25885
0,0,0,3,68,51,145,14,208,71,99,72,5,79,240,0,15,244,133,63,144,44,252,64,
 
25886
98,123,149,149,19,92,160,168,152,229,37,64,187,11,0,42,191,128,2,127,168,
 
25887
17,252,162,167,226,3,0,42,255,128,2,127,172,17,252,162,135,226,3,0,43,63,
 
25888
128,2,127,176,17,252,162,103,226,3,0,43,127,128,2,127,180,17,252,162,71,
 
25889
226,3,0,43,191,128,2,127,184,17,252,162,39,226,3,0,43,255,128,2,127,188,17,
 
25890
252,162,7,226,3,0,31,255,144,125,128,210,174,41,22,21,126,10,128,124,128,
 
25891
44,171,107,119,98,214,4,128,123,129,222,115,245,252,132,93,204,126,122,129,
 
25892
253,4,86,202,142,43,238,126,121,128,29,202,76,42,247,151,182,126,120,128,
 
25893
48,90,136,169,246,66,18,128,119,129,154,118,254,205,61,65,204,126,118,129,
 
25894
154,118,254,205,61,65,236,126,145,213,32,135,68,130,128,0,156,210,10,0,4,
 
25895
114,72,40,0,25,197,41,7,4,130,128,2,27,210,10,0,10,110,72,40,0,49,181,32,
 
25896
160,0,230,196,130,128,4,26,209,151,141,72,235,198,148,164,128,0,154,18,64,
 
25897
103,72,40,0,73,153,32,160,1,70,84,130,128,5,153,18,10,0,24,31,255,128,18,
 
25898
217,1,6,52,22,11,255,224,0,31,255,138,51,128,0,0,0,0,0,129,30,128,3,57,128,
 
25899
71,64,4,228,0,29,68,12,137,72,49,38,0,192,124,130,242,66,11,136,199,133,
 
25900
164,67,194,194,17,225,57,1,5,151,240,3,161,63,32,76,250,193,43,224,3,254,
 
25901
64,0,22,127,192,0,63,230,0,39,96,152,64,0,93,66,96,22,159,192,0,63,232,0,
 
25902
39,99,40,64,0,93,76,160,22,191,192,0,63,234,8,57,32,0,0,0,0,0,0,1,0,59,36,
 
25903
19,14,237,251,136,18,33,144,70,138,65,18,32,240,133,16,124,0,4,100,136,62,
 
25904
0,4,32,68,31,0,3,15,162,15,128,2,7,145,7,192,1,83,255,240,143,240,66,226,
 
25905
111,235,139,102,88,188,185,111,228,126,130,47,151,151,45,252,144,105,220,
 
25906
131,47,46,91,249,32,209,135,118,77,154,119,103,0,
 
25907
};
 
25908
#ifdef DUK_USE_INITJS
 
25909
const duk_uint8_t duk_initjs_data[] = {
 
25910
40,102,117,110,99,116,105,111,110,40,99,44,97,41,123,118,97,114,32,98,61,
 
25911
110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,41,59,79,98,106,
 
25912
101,99,116,46,100,101,102,105,110,101,80,114,111,112,101,114,116,121,40,97,
 
25913
46,76,111,103,103,101,114,44,34,99,108,111,103,34,44,123,118,97,108,117,
 
25914
101,58,98,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,109,101,
 
25915
114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,108,101,
 
25916
58,33,48,125,41,125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,
 
25917
59,10,0,
 
25918
};
 
25919
#endif  /* DUK_USE_INITJS */
 
25920
#elif defined(DUK_USE_DOUBLE_BE)
 
25921
const duk_uint8_t duk_strings_data[] = {
 
25922
55,86,227,24,145,55,102,120,144,3,63,94,228,54,100,137,186,26,20,164,137,
 
25923
186,50,11,164,109,77,215,5,61,35,106,3,25,110,8,22,158,130,38,163,8,217,
 
25924
200,158,76,156,210,117,128,153,203,210,70,46,137,187,18,27,164,187,201,209,
 
25925
130,100,55,91,70,4,145,63,66,231,44,128,105,187,41,197,13,49,122,8,196,24,
 
25926
71,75,70,138,104,115,77,215,5,36,20,217,255,122,45,26,47,186,156,104,79,
 
25927
253,119,253,253,22,139,70,139,232,190,234,113,161,63,245,223,247,244,90,
 
25928
106,26,95,162,251,169,198,132,255,214,255,223,209,105,13,47,209,125,212,
 
25929
227,66,127,235,127,239,232,180,208,55,232,190,234,113,161,63,245,255,247,
 
25930
244,90,163,70,66,253,23,221,78,52,39,254,174,110,234,220,110,202,113,67,76,
 
25931
65,45,198,10,194,210,148,19,2,202,72,197,209,37,129,22,148,100,13,12,89,
 
25932
196,2,32,226,11,12,172,153,197,72,196,141,153,162,73,81,132,56,156,199,128,
 
25933
83,42,100,230,136,169,147,155,115,4,18,39,219,125,160,206,75,140,100,16,
 
25934
200,209,12,168,104,140,33,128,83,34,208,210,17,13,43,143,82,70,72,115,70,
 
25935
70,213,4,140,102,120,186,201,36,98,40,144,19,33,196,230,61,11,34,55,18,24,
 
25936
32,145,15,185,158,36,0,213,178,161,160,90,50,72,159,98,2,214,66,19,108,3,
 
25937
203,176,68,210,46,230,116,73,27,120,190,201,104,105,15,185,58,145,17,15,
 
25938
186,130,36,109,79,181,146,228,109,79,186,130,44,3,209,178,186,44,2,228,157,
 
25939
135,19,32,156,50,23,109,37,230,125,204,17,49,38,109,212,11,161,14,247,33,
 
25940
179,36,76,26,20,164,138,103,16,8,131,4,192,165,161,164,235,104,192,146,40,
 
25941
42,22,78,180,12,32,158,34,202,96,18,157,217,158,46,183,103,135,147,164,140,
 
25942
93,19,244,116,84,192,242,24,64,90,200,70,117,13,168,22,129,253,7,70,9,144,
 
25943
191,183,245,223,93,245,223,186,47,138,248,144,253,0,126,176,95,91,246,2,
 
25944
250,191,176,15,216,39,235,122,134,149,13,68,240,159,171,234,26,84,53,19,
 
25945
194,58,134,149,13,68,240,103,5,36,20,205,41,197,13,49,155,70,4,145,56,92,
 
25946
229,144,13,77,26,50,21,13,32,211,41,197,13,50,11,129,204,13,36,161,25,142,
 
25947
72,105,98,234,52,102,136,26,55,48,111,117,134,196,52,108,5,198,183,24,165,
 
25948
91,157,17,146,239,24,157,34,8,136,89,65,48,55,236,136,9,129,164,4,144,210,
 
25949
0,78,144,192,25,23,210,132,103,246,71,244,161,25,253,142,190,200,94,122,13,
 
25950
229,184,223,99,246,4,47,150,227,125,145,7,229,183,236,137,229,183,236,126,
 
25951
192,61,33,216,73,72,6,33,26,6,16,168,107,233,50,161,163,37,201,245,31,127,
 
25952
247,95,82,149,130,83,234,26,50,93,44,162,230,133,161,164,82,12,215,68,157,
 
25953
16,36,67,73,212,136,136,73,146,83,33,46,65,46,110,241,153,57,122,113,67,76,
 
25954
121,18,125,193,1,19,152,147,238,8,8,154,110,242,100,230,174,110,242,36,233,
 
25955
122,113,67,76,185,187,212,152,165,233,197,13,51,164,73,250,147,17,125,69,
 
25956
175,184,32,34,185,18,125,45,22,190,224,128,138,228,73,250,147,19,60,230,
 
25957
204,232,145,39,214,57,179,58,164,73,250,147,16,252,9,144,242,36,250,48,76,
 
25958
139,145,39,234,76,71,243,169,25,34,68,159,78,234,70,77,145,39,234,76,76,
 
25959
242,27,73,146,74,145,39,214,33,180,153,36,217,18,126,164,197,47,16,78,104,
 
25960
228,169,18,125,145,4,230,142,82,145,39,234,76,76,242,22,180,72,130,115,71,
 
25961
39,200,147,235,16,181,162,68,19,154,57,30,68,159,102,134,18,38,36,251,52,
 
25962
48,153,115,73,215,20,178,36,228,98,79,212,152,153,228,45,104,145,4,230,142,
 
25963
79,49,39,214,33,107,68,136,39,52,114,105,137,63,82,98,151,136,39,52,114,81,
 
25964
137,62,200,130,115,71,38,152,147,245,38,38,121,13,164,201,37,24,147,235,16,
 
25965
218,76,146,89,137,63,82,98,63,157,72,201,6,36,250,119,82,50,73,137,63,82,
 
25966
98,31,129,131,24,147,232,193,133,24,147,245,38,33,248,19,33,204,73,244,96,
 
25967
153,22,98,79,212,152,153,231,54,103,65,137,62,177,205,153,220,98,79,212,
 
25968
152,139,234,45,125,193,1,21,152,147,233,104,181,247,4,4,78,98,79,179,67,9,
 
25969
41,187,171,112,128,178,118,104,97,59,41,197,13,52,166,238,173,194,2,201,
 
25970
209,130,100,236,167,20,52,204,155,187,52,48,157,148,226,134,153,147,119,70,
 
25971
9,147,178,156,80,211,13,174,176,253,73,136,175,4,100,69,205,221,124,72,36,
 
25972
73,14,107,102,238,146,239,115,72,217,160,11,60,221,210,162,228,28,124,247,
 
25973
73,19,69,73,164,52,168,106,39,136,249,164,48,38,138,147,72,105,80,212,79,3,
 
25974
235,65,214,167,204,67,117,80,46,132,79,152,11,234,160,93,8,105,80,50,156,
 
25975
73,56,161,145,155,186,183,8,11,39,104,247,146,61,16,36,69,205,221,163,222,
 
25976
72,244,64,145,35,55,117,110,16,22,78,173,214,36,122,32,72,139,155,186,183,
 
25977
88,145,232,129,34,38,84,12,167,20,52,197,147,214,137,154,68,4,68,115,196,
 
25978
143,88,4,66,176,19,17,218,183,8,11,39,68,230,60,17,34,132,112,71,162,112,
 
25979
201,208,76,194,56,35,208,77,133,139,153,209,28,17,232,156,50,46,36,29,4,78,
 
25980
197,6,60,205,18,14,130,33,138,133,204,145,27,0,243,149,209,233,0,35,146,78,
 
25981
97,10,74,146,56,90,193,41,245,13,25,47,215,20,232,104,201,126,184,167,163,
 
25982
100,116,22,102,147,214,129,16,146,116,102,89,45,2,33,100,116,22,103,137,42,
 
25983
72,200,132,125,36,113,189,207,34,92,134,152,78,104,129,51,162,93,4,98,12,
 
25984
36,17,53,24,70,206,70,16,22,178,68,129,67,70,65,1,107,40,30,245,226,143,
 
25985
139,158,72,207,29,68,186,70,209,132,136,2,178,53,18,235,226,233,186,120,
 
25986
121,58,226,184,224,151,93,102,245,241,115,201,25,224,245,2,232,78,184,174,
 
25987
155,186,183,8,11,39,101,56,161,166,68,221,217,78,40,105,150,39,54,83,141,5,
 
25988
55,68,114,36,198,98,77,68,109,24,72,128,43,35,4,230,149,6,164,64,21,145,22,
 
25989
138,38,0,172,133,168,23,66,17,68,196,152,137,116,151,153,27,36,5,100,66,37,
 
25990
210,197,217,35,80,137,118,68,2,200,56,190,36,169,27,62,146,243,35,100,135,
 
25991
54,70,44,72,76,144,146,32,23,1,144,168,105,58,248,185,228,140,208,73,56,
 
25992
100,42,26,78,190,46,121,35,60,24,81,32,38,73,152,147,235,172,222,190,46,
 
25993
121,35,60,117,160,97,37,131,18,125,117,155,215,197,207,36,103,142,140,146,
 
25994
20,80,249,186,46,49,39,215,197,211,116,240,242,117,197,75,226,233,186,120,
 
25995
121,12,178,52,211,57,64,178,70,101,124,80,217,162,141,36,132,7,144,196,144,
 
25996
128,242,72,141,19,134,79,82,40,23,156,199,185,164,108,210,70,137,195,39,
 
25997
169,20,72,100,19,134,79,82,40,23,156,199,185,164,108,210,50,9,195,39,169,
 
25998
20,33,18,233,80,212,76,133,68,186,208,117,170,120,35,34,116,171,112,38,135,
 
25999
130,50,39,80,217,144,149,2,209,234,69,4,244,98,232,167,179,195,201,210,70,
 
26000
46,138,251,44,54,96,191,73,24,186,46,236,72,82,68,141,17,58,72,197,209,87,
 
26001
98,6,152,157,36,98,232,167,164,168,23,210,70,46,137,67,18,1,68,16,36,66,
 
26002
136,19,17,208,39,54,104,109,8,129,144,52,49,137,19,140,133,5,23,51,12,139,
 
26003
36,200,33,184,132,92,136,114,161,160,90,240,50,186,40,45,26,41,161,205,18,
 
26004
10,36,53,72,108,166,6,136,142,40,218,75,26,36,157,34,211,74,200,152,142,73,
 
26005
157,18,44,207,23,88,115,142,13,60,60,142,40,234,8,146,174,64,203,99,161,
 
26006
100,37,145,51,148,75,4,164,81,57,178,153,8,218,48,196,187,221,25,156,151,
 
26007
153,26,57,25,12,123,163,50,202,143,36,72,218,45,100,156,104,66,148,11,145,
 
26008
20,134,61,100,97,27,57,37,13,153,34,80,8,131,89,38,119,128,74,1,136,119,
 
26009
197,21,4,200,151,197,211,32,166,65,153,244,10,208,35,74,96,154,4,92,32,139,
 
26010
24,
 
26011
};
 
26012
 
 
26013
/* to convert a heap stridx to a token number, subtract
 
26014
 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
 
26015
 */
 
26016
 
 
26017
/* native functions: 128 */
 
26018
const duk_c_function duk_bi_native_functions[] = {
 
26019
        (duk_c_function) duk_bi_array_constructor,
 
26020
        (duk_c_function) duk_bi_array_constructor_is_array,
 
26021
        (duk_c_function) duk_bi_array_prototype_concat,
 
26022
        (duk_c_function) duk_bi_array_prototype_indexof_shared,
 
26023
        (duk_c_function) duk_bi_array_prototype_iter_shared,
 
26024
        (duk_c_function) duk_bi_array_prototype_join_shared,
 
26025
        (duk_c_function) duk_bi_array_prototype_pop,
 
26026
        (duk_c_function) duk_bi_array_prototype_push,
 
26027
        (duk_c_function) duk_bi_array_prototype_reduce_shared,
 
26028
        (duk_c_function) duk_bi_array_prototype_reverse,
 
26029
        (duk_c_function) duk_bi_array_prototype_shift,
 
26030
        (duk_c_function) duk_bi_array_prototype_slice,
 
26031
        (duk_c_function) duk_bi_array_prototype_sort,
 
26032
        (duk_c_function) duk_bi_array_prototype_splice,
 
26033
        (duk_c_function) duk_bi_array_prototype_to_string,
 
26034
        (duk_c_function) duk_bi_array_prototype_unshift,
 
26035
        (duk_c_function) duk_bi_boolean_constructor,
 
26036
        (duk_c_function) duk_bi_boolean_prototype_tostring_shared,
 
26037
        (duk_c_function) duk_bi_buffer_constructor,
 
26038
        (duk_c_function) duk_bi_buffer_prototype_tostring_shared,
 
26039
        (duk_c_function) duk_bi_date_constructor,
 
26040
        (duk_c_function) duk_bi_date_constructor_now,
 
26041
        (duk_c_function) duk_bi_date_constructor_parse,
 
26042
        (duk_c_function) duk_bi_date_constructor_utc,
 
26043
        (duk_c_function) duk_bi_date_prototype_get_shared,
 
26044
        (duk_c_function) duk_bi_date_prototype_get_timezone_offset,
 
26045
        (duk_c_function) duk_bi_date_prototype_set_shared,
 
26046
        (duk_c_function) duk_bi_date_prototype_set_time,
 
26047
        (duk_c_function) duk_bi_date_prototype_to_json,
 
26048
        (duk_c_function) duk_bi_date_prototype_tostring_shared,
 
26049
        (duk_c_function) duk_bi_date_prototype_value_of,
 
26050
        (duk_c_function) duk_bi_duktape_object_act,
 
26051
        (duk_c_function) duk_bi_duktape_object_compact,
 
26052
        (duk_c_function) duk_bi_duktape_object_dec,
 
26053
        (duk_c_function) duk_bi_duktape_object_enc,
 
26054
        (duk_c_function) duk_bi_duktape_object_fin,
 
26055
        (duk_c_function) duk_bi_duktape_object_gc,
 
26056
        (duk_c_function) duk_bi_duktape_object_info,
 
26057
        (duk_c_function) duk_bi_duktape_object_line,
 
26058
        (duk_c_function) duk_bi_error_constructor_shared,
 
26059
        (duk_c_function) duk_bi_error_prototype_filename_getter,
 
26060
        (duk_c_function) duk_bi_error_prototype_linenumber_getter,
 
26061
        (duk_c_function) duk_bi_error_prototype_nop_setter,
 
26062
        (duk_c_function) duk_bi_error_prototype_stack_getter,
 
26063
        (duk_c_function) duk_bi_error_prototype_to_string,
 
26064
        (duk_c_function) duk_bi_function_constructor,
 
26065
        (duk_c_function) duk_bi_function_prototype,
 
26066
        (duk_c_function) duk_bi_function_prototype_apply,
 
26067
        (duk_c_function) duk_bi_function_prototype_bind,
 
26068
        (duk_c_function) duk_bi_function_prototype_call,
 
26069
        (duk_c_function) duk_bi_function_prototype_to_string,
 
26070
        (duk_c_function) duk_bi_global_object_alert,
 
26071
        (duk_c_function) duk_bi_global_object_decode_uri,
 
26072
        (duk_c_function) duk_bi_global_object_decode_uri_component,
 
26073
        (duk_c_function) duk_bi_global_object_encode_uri,
 
26074
        (duk_c_function) duk_bi_global_object_encode_uri_component,
 
26075
        (duk_c_function) duk_bi_global_object_escape,
 
26076
        (duk_c_function) duk_bi_global_object_eval,
 
26077
        (duk_c_function) duk_bi_global_object_is_finite,
 
26078
        (duk_c_function) duk_bi_global_object_is_nan,
 
26079
        (duk_c_function) duk_bi_global_object_parse_float,
 
26080
        (duk_c_function) duk_bi_global_object_parse_int,
 
26081
        (duk_c_function) duk_bi_global_object_print,
 
26082
        (duk_c_function) duk_bi_global_object_unescape,
 
26083
        (duk_c_function) duk_bi_json_object_parse,
 
26084
        (duk_c_function) duk_bi_json_object_stringify,
 
26085
        (duk_c_function) duk_bi_logger_constructor,
 
26086
        (duk_c_function) duk_bi_logger_prototype_fmt,
 
26087
        (duk_c_function) duk_bi_logger_prototype_log_shared,
 
26088
        (duk_c_function) duk_bi_logger_prototype_raw,
 
26089
        (duk_c_function) duk_bi_math_object_max,
 
26090
        (duk_c_function) duk_bi_math_object_min,
 
26091
        (duk_c_function) duk_bi_math_object_onearg_shared,
 
26092
        (duk_c_function) duk_bi_math_object_random,
 
26093
        (duk_c_function) duk_bi_math_object_twoarg_shared,
 
26094
        (duk_c_function) duk_bi_number_constructor,
 
26095
        (duk_c_function) duk_bi_number_prototype_to_exponential,
 
26096
        (duk_c_function) duk_bi_number_prototype_to_fixed,
 
26097
        (duk_c_function) duk_bi_number_prototype_to_locale_string,
 
26098
        (duk_c_function) duk_bi_number_prototype_to_precision,
 
26099
        (duk_c_function) duk_bi_number_prototype_to_string,
 
26100
        (duk_c_function) duk_bi_number_prototype_value_of,
 
26101
        (duk_c_function) duk_bi_object_constructor,
 
26102
        (duk_c_function) duk_bi_object_constructor_create,
 
26103
        (duk_c_function) duk_bi_object_constructor_define_properties,
 
26104
        (duk_c_function) duk_bi_object_constructor_define_property,
 
26105
        (duk_c_function) duk_bi_object_constructor_get_own_property_descriptor,
 
26106
        (duk_c_function) duk_bi_object_constructor_get_own_property_names,
 
26107
        (duk_c_function) duk_bi_object_constructor_get_prototype_of,
 
26108
        (duk_c_function) duk_bi_object_constructor_is_extensible,
 
26109
        (duk_c_function) duk_bi_object_constructor_is_sealed_frozen_shared,
 
26110
        (duk_c_function) duk_bi_object_constructor_keys,
 
26111
        (duk_c_function) duk_bi_object_constructor_prevent_extensions,
 
26112
        (duk_c_function) duk_bi_object_constructor_seal_freeze_shared,
 
26113
        (duk_c_function) duk_bi_object_prototype_has_own_property,
 
26114
        (duk_c_function) duk_bi_object_prototype_is_prototype_of,
 
26115
        (duk_c_function) duk_bi_object_prototype_property_is_enumerable,
 
26116
        (duk_c_function) duk_bi_object_prototype_to_locale_string,
 
26117
        (duk_c_function) duk_bi_object_prototype_to_string,
 
26118
        (duk_c_function) duk_bi_object_prototype_value_of,
 
26119
        (duk_c_function) duk_bi_pointer_constructor,
 
26120
        (duk_c_function) duk_bi_pointer_prototype_tostring_shared,
 
26121
        (duk_c_function) duk_bi_regexp_constructor,
 
26122
        (duk_c_function) duk_bi_regexp_prototype_exec,
 
26123
        (duk_c_function) duk_bi_regexp_prototype_test,
 
26124
        (duk_c_function) duk_bi_regexp_prototype_to_string,
 
26125
        (duk_c_function) duk_bi_string_constructor,
 
26126
        (duk_c_function) duk_bi_string_constructor_from_char_code,
 
26127
        (duk_c_function) duk_bi_string_prototype_caseconv_shared,
 
26128
        (duk_c_function) duk_bi_string_prototype_char_at,
 
26129
        (duk_c_function) duk_bi_string_prototype_char_code_at,
 
26130
        (duk_c_function) duk_bi_string_prototype_concat,
 
26131
        (duk_c_function) duk_bi_string_prototype_indexof_shared,
 
26132
        (duk_c_function) duk_bi_string_prototype_locale_compare,
 
26133
        (duk_c_function) duk_bi_string_prototype_match,
 
26134
        (duk_c_function) duk_bi_string_prototype_replace,
 
26135
        (duk_c_function) duk_bi_string_prototype_search,
 
26136
        (duk_c_function) duk_bi_string_prototype_slice,
 
26137
        (duk_c_function) duk_bi_string_prototype_split,
 
26138
        (duk_c_function) duk_bi_string_prototype_substr,
 
26139
        (duk_c_function) duk_bi_string_prototype_substring,
 
26140
        (duk_c_function) duk_bi_string_prototype_to_string,
 
26141
        (duk_c_function) duk_bi_string_prototype_trim,
 
26142
        (duk_c_function) duk_bi_thread_constructor,
 
26143
        (duk_c_function) duk_bi_thread_current,
 
26144
        (duk_c_function) duk_bi_thread_resume,
 
26145
        (duk_c_function) duk_bi_thread_yield,
 
26146
        (duk_c_function) duk_bi_type_error_thrower,
 
26147
};
 
26148
 
 
26149
const duk_uint8_t duk_builtins_data[] = {
 
26150
105,195,74,144,77,40,105,45,9,124,104,46,3,3,72,0,71,225,65,165,168,33,243,
 
26151
6,145,0,122,24,210,150,14,249,35,120,160,55,226,13,76,192,196,177,164,156,
 
26152
22,192,4,202,52,147,197,88,0,169,70,146,120,163,0,23,40,210,79,19,96,3,37,
 
26153
26,73,226,76,0,108,163,73,60,69,128,14,148,105,39,136,48,1,242,144,56,208,
 
26154
254,80,10,26,94,192,63,72,105,18,1,253,1,165,144,5,244,70,148,32,7,202,20,
 
26155
31,255,170,188,128,255,240,0,0,0,0,0,0,93,128,255,224,0,0,0,0,0,0,98,136,
 
26156
19,48,130,70,32,68,198,8,25,0,243,40,28,102,3,76,224,97,160,11,52,162,166,
 
26157
164,80,214,137,155,17,35,106,34,110,68,13,224,81,192,9,56,74,39,25,176,243,
 
26158
146,67,143,81,13,60,36,48,236,144,179,162,66,141,9,9,53,36,32,216,144,115,
 
26159
114,65,142,9,5,63,36,16,248,122,6,102,61,255,255,130,71,134,0,2,135,248,6,
 
26160
192,22,8,255,86,67,249,92,143,213,52,63,21,88,251,84,67,233,116,143,149,
 
26161
210,128,0,190,23,8,247,90,35,217,104,160,0,47,85,146,61,22,201,255,225,0,
 
26162
51,177,136,14,182,16,58,152,192,233,94,35,161,124,142,118,2,10,47,224,0,31,
 
26163
226,0,35,176,200,14,98,244,57,76,79,156,134,7,194,143,248,0,184,64,72,31,
 
26164
227,0,171,176,56,14,176,80,128,0,184,0,143,155,224,164,111,3,1,186,14,124,
 
26165
220,9,3,108,40,13,160,180,54,67,8,216,13,94,107,135,159,53,128,207,192,0,
 
26166
90,160,103,255,255,237,64,67,70,152,33,168,0,11,72,16,212,0,9,162,8,106,0,
 
26167
6,208,4,53,0,4,103,132,31,128,0,179,130,15,255,255,197,39,240,1,102,181,
 
26168
159,7,249,0,146,33,1,148,118,60,129,212,242,6,99,105,25,109,196,112,55,159,
 
26169
53,156,13,26,174,6,160,0,44,167,18,50,92,136,200,115,67,29,208,141,167,84,
 
26170
49,157,144,197,120,67,17,176,12,54,192,48,155,2,0,2,193,108,8,0,11,1,232,
 
26171
11,247,116,10,95,224,0,31,229,2,72,140,19,176,68,32,0,46,161,16,10,111,226,
 
26172
175,160,63,247,255,255,255,255,255,255,175,96,0,0,0,0,0,0,0,0,175,32,63,
 
26173
252,0,0,0,0,0,0,46,160,63,248,0,0,0,0,0,0,46,224,127,248,0,0,0,0,0,0,0,31,
 
26174
230,2,72,128,0,0,0,0,0,0,0,0,51,177,64,142,180,226,58,148,64,185,77,34,225,
 
26175
48,139,116,242,10,127,224,6,182,22,34,212,95,249,104,42,0,255,56,18,68,135,
 
26176
255,128,0,0,0,0,0,11,93,131,161,0,104,89,142,132,0,161,100,58,16,4,135,88,
 
26177
232,64,58,22,35,161,0,168,88,14,132,3,33,28,58,16,6,4,104,232,65,24,145,
 
26178
131,132,117,15,1,94,60,5,112,192,64,2,21,163,0,86,12,4,64,33,86,48,17,0,5,
 
26179
80,192,72,3,21,35,1,32,4,84,12,5,192,33,78,48,23,0,5,48,192,76,2,20,163,1,
 
26180
48,0,82,12,5,0,33,70,48,20,0,5,16,192,84,2,20,35,1,80,0,80,12,5,128,33,62,
 
26181
48,22,0,4,240,200,19,163,100,78,13,20,68,33,54,52,81,16,4,208,210,249,8,66,
 
26182
100,105,124,132,1,48,52,254,98,16,151,26,127,49,0,75,13,79,160,132,37,70,
 
26183
167,208,64,18,131,69,16,8,73,141,20,64,1,36,52,190,64,16,145,26,95,32,0,72,
 
26184
13,63,152,4,163,198,159,204,0,81,99,1,0,24,69,13,20,200,4,84,127,0,0,255,
 
26185
64,98,44,16,48,0,128,161,161,32,128,241,144,177,144,145,144,114,0,0,0,0,0,
 
26186
0,0,0,3,68,51,145,14,208,71,99,72,5,79,240,0,15,244,133,63,144,44,252,64,
 
26187
98,123,149,149,19,92,160,168,152,229,37,64,187,11,0,42,191,128,2,127,168,
 
26188
17,252,162,167,226,3,0,42,255,128,2,127,172,17,252,162,135,226,3,0,43,63,
 
26189
128,2,127,176,17,252,162,103,226,3,0,43,127,128,2,127,180,17,252,162,71,
 
26190
226,3,0,43,191,128,2,127,184,17,252,162,39,226,3,0,43,255,128,2,127,188,17,
 
26191
252,162,7,226,3,0,31,255,144,125,128,128,11,126,21,22,40,174,210,124,128,
 
26192
128,4,215,99,119,106,170,44,123,128,127,204,92,133,253,244,115,222,122,128,
 
26193
127,238,42,142,202,87,5,252,121,128,127,183,150,246,42,77,202,28,120,128,
 
26194
128,18,67,246,168,136,90,48,119,128,127,205,65,60,204,254,119,154,118,128,
 
26195
127,237,65,60,204,254,119,154,145,213,32,135,68,130,128,0,156,210,10,0,4,
 
26196
114,72,40,0,25,197,41,7,4,130,128,2,27,210,10,0,10,110,72,40,0,49,181,32,
 
26197
160,0,230,196,130,128,4,26,209,151,141,72,235,198,148,164,128,0,154,18,64,
 
26198
103,72,40,0,73,153,32,160,1,70,84,130,128,5,153,18,10,0,24,31,255,128,18,
 
26199
217,1,6,52,22,11,255,224,0,31,255,138,51,128,129,30,128,0,0,0,0,0,3,57,128,
 
26200
71,64,4,228,0,29,68,12,137,72,49,38,0,192,124,130,242,66,11,136,199,133,
 
26201
164,67,194,194,17,225,57,1,5,151,240,3,161,63,32,76,250,193,43,224,3,254,
 
26202
64,0,22,127,192,0,63,230,0,39,96,152,64,0,93,66,96,22,159,192,0,63,232,0,
 
26203
39,99,40,64,0,93,76,160,22,191,192,0,63,234,8,57,33,0,0,0,0,0,0,0,0,59,36,
 
26204
19,14,237,251,136,18,33,144,70,138,65,18,32,240,133,16,124,0,4,100,136,62,
 
26205
0,4,32,68,31,0,3,15,162,15,128,2,7,145,7,192,1,83,255,240,143,240,66,226,
 
26206
111,235,139,102,88,188,185,111,228,126,130,47,151,151,45,252,144,105,220,
 
26207
131,47,46,91,249,32,209,135,118,77,154,119,103,0,
 
26208
};
 
26209
#ifdef DUK_USE_INITJS
 
26210
const duk_uint8_t duk_initjs_data[] = {
 
26211
40,102,117,110,99,116,105,111,110,40,99,44,97,41,123,118,97,114,32,98,61,
 
26212
110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,41,59,79,98,106,
 
26213
101,99,116,46,100,101,102,105,110,101,80,114,111,112,101,114,116,121,40,97,
 
26214
46,76,111,103,103,101,114,44,34,99,108,111,103,34,44,123,118,97,108,117,
 
26215
101,58,98,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,109,101,
 
26216
114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,108,101,
 
26217
58,33,48,125,41,125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,
 
26218
59,10,0,
 
26219
};
 
26220
#endif  /* DUK_USE_INITJS */
 
26221
#elif defined(DUK_USE_DOUBLE_ME)
 
26222
const duk_uint8_t duk_strings_data[] = {
 
26223
55,86,227,24,145,55,102,120,144,3,63,94,228,54,100,137,186,26,20,164,137,
 
26224
186,50,11,164,109,77,215,5,61,35,106,3,25,110,8,22,158,130,38,163,8,217,
 
26225
200,158,76,156,210,117,128,153,203,210,70,46,137,187,18,27,164,187,201,209,
 
26226
130,100,55,91,70,4,145,63,66,231,44,128,105,187,41,197,13,49,122,8,196,24,
 
26227
71,75,70,138,104,115,77,215,5,36,20,217,255,122,45,26,47,186,156,104,79,
 
26228
253,119,253,253,22,139,70,139,232,190,234,113,161,63,245,223,247,244,90,
 
26229
106,26,95,162,251,169,198,132,255,214,255,223,209,105,13,47,209,125,212,
 
26230
227,66,127,235,127,239,232,180,208,55,232,190,234,113,161,63,245,255,247,
 
26231
244,90,163,70,66,253,23,221,78,52,39,254,174,110,234,220,110,202,113,67,76,
 
26232
65,45,198,10,194,210,148,19,2,202,72,197,209,37,129,22,148,100,13,12,89,
 
26233
196,2,32,226,11,12,172,153,197,72,196,141,153,162,73,81,132,56,156,199,128,
 
26234
83,42,100,230,136,169,147,155,115,4,18,39,219,125,160,206,75,140,100,16,
 
26235
200,209,12,168,104,140,33,128,83,34,208,210,17,13,43,143,82,70,72,115,70,
 
26236
70,213,4,140,102,120,186,201,36,98,40,144,19,33,196,230,61,11,34,55,18,24,
 
26237
32,145,15,185,158,36,0,213,178,161,160,90,50,72,159,98,2,214,66,19,108,3,
 
26238
203,176,68,210,46,230,116,73,27,120,190,201,104,105,15,185,58,145,17,15,
 
26239
186,130,36,109,79,181,146,228,109,79,186,130,44,3,209,178,186,44,2,228,157,
 
26240
135,19,32,156,50,23,109,37,230,125,204,17,49,38,109,212,11,161,14,247,33,
 
26241
179,36,76,26,20,164,138,103,16,8,131,4,192,165,161,164,235,104,192,146,40,
 
26242
42,22,78,180,12,32,158,34,202,96,18,157,217,158,46,183,103,135,147,164,140,
 
26243
93,19,244,116,84,192,242,24,64,90,200,70,117,13,168,22,129,253,7,70,9,144,
 
26244
191,183,245,223,93,245,223,186,47,138,248,144,253,0,126,176,95,91,246,2,
 
26245
250,191,176,15,216,39,235,122,134,149,13,68,240,159,171,234,26,84,53,19,
 
26246
194,58,134,149,13,68,240,103,5,36,20,205,41,197,13,49,155,70,4,145,56,92,
 
26247
229,144,13,77,26,50,21,13,32,211,41,197,13,50,11,129,204,13,36,161,25,142,
 
26248
72,105,98,234,52,102,136,26,55,48,111,117,134,196,52,108,5,198,183,24,165,
 
26249
91,157,17,146,239,24,157,34,8,136,89,65,48,55,236,136,9,129,164,4,144,210,
 
26250
0,78,144,192,25,23,210,132,103,246,71,244,161,25,253,142,190,200,94,122,13,
 
26251
229,184,223,99,246,4,47,150,227,125,145,7,229,183,236,137,229,183,236,126,
 
26252
192,61,33,216,73,72,6,33,26,6,16,168,107,233,50,161,163,37,201,245,31,127,
 
26253
247,95,82,149,130,83,234,26,50,93,44,162,230,133,161,164,82,12,215,68,157,
 
26254
16,36,67,73,212,136,136,73,146,83,33,46,65,46,110,241,153,57,122,113,67,76,
 
26255
121,18,125,193,1,19,152,147,238,8,8,154,110,242,100,230,174,110,242,36,233,
 
26256
122,113,67,76,185,187,212,152,165,233,197,13,51,164,73,250,147,17,125,69,
 
26257
175,184,32,34,185,18,125,45,22,190,224,128,138,228,73,250,147,19,60,230,
 
26258
204,232,145,39,214,57,179,58,164,73,250,147,16,252,9,144,242,36,250,48,76,
 
26259
139,145,39,234,76,71,243,169,25,34,68,159,78,234,70,77,145,39,234,76,76,
 
26260
242,27,73,146,74,145,39,214,33,180,153,36,217,18,126,164,197,47,16,78,104,
 
26261
228,169,18,125,145,4,230,142,82,145,39,234,76,76,242,22,180,72,130,115,71,
 
26262
39,200,147,235,16,181,162,68,19,154,57,30,68,159,102,134,18,38,36,251,52,
 
26263
48,153,115,73,215,20,178,36,228,98,79,212,152,153,228,45,104,145,4,230,142,
 
26264
79,49,39,214,33,107,68,136,39,52,114,105,137,63,82,98,151,136,39,52,114,81,
 
26265
137,62,200,130,115,71,38,152,147,245,38,38,121,13,164,201,37,24,147,235,16,
 
26266
218,76,146,89,137,63,82,98,63,157,72,201,6,36,250,119,82,50,73,137,63,82,
 
26267
98,31,129,131,24,147,232,193,133,24,147,245,38,33,248,19,33,204,73,244,96,
 
26268
153,22,98,79,212,152,153,231,54,103,65,137,62,177,205,153,220,98,79,212,
 
26269
152,139,234,45,125,193,1,21,152,147,233,104,181,247,4,4,78,98,79,179,67,9,
 
26270
41,187,171,112,128,178,118,104,97,59,41,197,13,52,166,238,173,194,2,201,
 
26271
209,130,100,236,167,20,52,204,155,187,52,48,157,148,226,134,153,147,119,70,
 
26272
9,147,178,156,80,211,13,174,176,253,73,136,175,4,100,69,205,221,124,72,36,
 
26273
73,14,107,102,238,146,239,115,72,217,160,11,60,221,210,162,228,28,124,247,
 
26274
73,19,69,73,164,52,168,106,39,136,249,164,48,38,138,147,72,105,80,212,79,3,
 
26275
235,65,214,167,204,67,117,80,46,132,79,152,11,234,160,93,8,105,80,50,156,
 
26276
73,56,161,145,155,186,183,8,11,39,104,247,146,61,16,36,69,205,221,163,222,
 
26277
72,244,64,145,35,55,117,110,16,22,78,173,214,36,122,32,72,139,155,186,183,
 
26278
88,145,232,129,34,38,84,12,167,20,52,197,147,214,137,154,68,4,68,115,196,
 
26279
143,88,4,66,176,19,17,218,183,8,11,39,68,230,60,17,34,132,112,71,162,112,
 
26280
201,208,76,194,56,35,208,77,133,139,153,209,28,17,232,156,50,46,36,29,4,78,
 
26281
197,6,60,205,18,14,130,33,138,133,204,145,27,0,243,149,209,233,0,35,146,78,
 
26282
97,10,74,146,56,90,193,41,245,13,25,47,215,20,232,104,201,126,184,167,163,
 
26283
100,116,22,102,147,214,129,16,146,116,102,89,45,2,33,100,116,22,103,137,42,
 
26284
72,200,132,125,36,113,189,207,34,92,134,152,78,104,129,51,162,93,4,98,12,
 
26285
36,17,53,24,70,206,70,16,22,178,68,129,67,70,65,1,107,40,30,245,226,143,
 
26286
139,158,72,207,29,68,186,70,209,132,136,2,178,53,18,235,226,233,186,120,
 
26287
121,58,226,184,224,151,93,102,245,241,115,201,25,224,245,2,232,78,184,174,
 
26288
155,186,183,8,11,39,101,56,161,166,68,221,217,78,40,105,150,39,54,83,141,5,
 
26289
55,68,114,36,198,98,77,68,109,24,72,128,43,35,4,230,149,6,164,64,21,145,22,
 
26290
138,38,0,172,133,168,23,66,17,68,196,152,137,116,151,153,27,36,5,100,66,37,
 
26291
210,197,217,35,80,137,118,68,2,200,56,190,36,169,27,62,146,243,35,100,135,
 
26292
54,70,44,72,76,144,146,32,23,1,144,168,105,58,248,185,228,140,208,73,56,
 
26293
100,42,26,78,190,46,121,35,60,24,81,32,38,73,152,147,235,172,222,190,46,
 
26294
121,35,60,117,160,97,37,131,18,125,117,155,215,197,207,36,103,142,140,146,
 
26295
20,80,249,186,46,49,39,215,197,211,116,240,242,117,197,75,226,233,186,120,
 
26296
121,12,178,52,211,57,64,178,70,101,124,80,217,162,141,36,132,7,144,196,144,
 
26297
128,242,72,141,19,134,79,82,40,23,156,199,185,164,108,210,70,137,195,39,
 
26298
169,20,72,100,19,134,79,82,40,23,156,199,185,164,108,210,50,9,195,39,169,
 
26299
20,33,18,233,80,212,76,133,68,186,208,117,170,120,35,34,116,171,112,38,135,
 
26300
130,50,39,80,217,144,149,2,209,234,69,4,244,98,232,167,179,195,201,210,70,
 
26301
46,138,251,44,54,96,191,73,24,186,46,236,72,82,68,141,17,58,72,197,209,87,
 
26302
98,6,152,157,36,98,232,167,164,168,23,210,70,46,137,67,18,1,68,16,36,66,
 
26303
136,19,17,208,39,54,104,109,8,129,144,52,49,137,19,140,133,5,23,51,12,139,
 
26304
36,200,33,184,132,92,136,114,161,160,90,240,50,186,40,45,26,41,161,205,18,
 
26305
10,36,53,72,108,166,6,136,142,40,218,75,26,36,157,34,211,74,200,152,142,73,
 
26306
157,18,44,207,23,88,115,142,13,60,60,142,40,234,8,146,174,64,203,99,161,
 
26307
100,37,145,51,148,75,4,164,81,57,178,153,8,218,48,196,187,221,25,156,151,
 
26308
153,26,57,25,12,123,163,50,202,143,36,72,218,45,100,156,104,66,148,11,145,
 
26309
20,134,61,100,97,27,57,37,13,153,34,80,8,131,89,38,119,128,74,1,136,119,
 
26310
197,21,4,200,151,197,211,32,166,65,153,244,10,208,35,74,96,154,4,92,32,139,
 
26311
24,
 
26312
};
 
26313
 
 
26314
/* to convert a heap stridx to a token number, subtract
 
26315
 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
 
26316
 */
 
26317
 
 
26318
/* native functions: 128 */
 
26319
const duk_c_function duk_bi_native_functions[] = {
 
26320
        (duk_c_function) duk_bi_array_constructor,
 
26321
        (duk_c_function) duk_bi_array_constructor_is_array,
 
26322
        (duk_c_function) duk_bi_array_prototype_concat,
 
26323
        (duk_c_function) duk_bi_array_prototype_indexof_shared,
 
26324
        (duk_c_function) duk_bi_array_prototype_iter_shared,
 
26325
        (duk_c_function) duk_bi_array_prototype_join_shared,
 
26326
        (duk_c_function) duk_bi_array_prototype_pop,
 
26327
        (duk_c_function) duk_bi_array_prototype_push,
 
26328
        (duk_c_function) duk_bi_array_prototype_reduce_shared,
 
26329
        (duk_c_function) duk_bi_array_prototype_reverse,
 
26330
        (duk_c_function) duk_bi_array_prototype_shift,
 
26331
        (duk_c_function) duk_bi_array_prototype_slice,
 
26332
        (duk_c_function) duk_bi_array_prototype_sort,
 
26333
        (duk_c_function) duk_bi_array_prototype_splice,
 
26334
        (duk_c_function) duk_bi_array_prototype_to_string,
 
26335
        (duk_c_function) duk_bi_array_prototype_unshift,
 
26336
        (duk_c_function) duk_bi_boolean_constructor,
 
26337
        (duk_c_function) duk_bi_boolean_prototype_tostring_shared,
 
26338
        (duk_c_function) duk_bi_buffer_constructor,
 
26339
        (duk_c_function) duk_bi_buffer_prototype_tostring_shared,
 
26340
        (duk_c_function) duk_bi_date_constructor,
 
26341
        (duk_c_function) duk_bi_date_constructor_now,
 
26342
        (duk_c_function) duk_bi_date_constructor_parse,
 
26343
        (duk_c_function) duk_bi_date_constructor_utc,
 
26344
        (duk_c_function) duk_bi_date_prototype_get_shared,
 
26345
        (duk_c_function) duk_bi_date_prototype_get_timezone_offset,
 
26346
        (duk_c_function) duk_bi_date_prototype_set_shared,
 
26347
        (duk_c_function) duk_bi_date_prototype_set_time,
 
26348
        (duk_c_function) duk_bi_date_prototype_to_json,
 
26349
        (duk_c_function) duk_bi_date_prototype_tostring_shared,
 
26350
        (duk_c_function) duk_bi_date_prototype_value_of,
 
26351
        (duk_c_function) duk_bi_duktape_object_act,
 
26352
        (duk_c_function) duk_bi_duktape_object_compact,
 
26353
        (duk_c_function) duk_bi_duktape_object_dec,
 
26354
        (duk_c_function) duk_bi_duktape_object_enc,
 
26355
        (duk_c_function) duk_bi_duktape_object_fin,
 
26356
        (duk_c_function) duk_bi_duktape_object_gc,
 
26357
        (duk_c_function) duk_bi_duktape_object_info,
 
26358
        (duk_c_function) duk_bi_duktape_object_line,
 
26359
        (duk_c_function) duk_bi_error_constructor_shared,
 
26360
        (duk_c_function) duk_bi_error_prototype_filename_getter,
 
26361
        (duk_c_function) duk_bi_error_prototype_linenumber_getter,
 
26362
        (duk_c_function) duk_bi_error_prototype_nop_setter,
 
26363
        (duk_c_function) duk_bi_error_prototype_stack_getter,
 
26364
        (duk_c_function) duk_bi_error_prototype_to_string,
 
26365
        (duk_c_function) duk_bi_function_constructor,
 
26366
        (duk_c_function) duk_bi_function_prototype,
 
26367
        (duk_c_function) duk_bi_function_prototype_apply,
 
26368
        (duk_c_function) duk_bi_function_prototype_bind,
 
26369
        (duk_c_function) duk_bi_function_prototype_call,
 
26370
        (duk_c_function) duk_bi_function_prototype_to_string,
 
26371
        (duk_c_function) duk_bi_global_object_alert,
 
26372
        (duk_c_function) duk_bi_global_object_decode_uri,
 
26373
        (duk_c_function) duk_bi_global_object_decode_uri_component,
 
26374
        (duk_c_function) duk_bi_global_object_encode_uri,
 
26375
        (duk_c_function) duk_bi_global_object_encode_uri_component,
 
26376
        (duk_c_function) duk_bi_global_object_escape,
 
26377
        (duk_c_function) duk_bi_global_object_eval,
 
26378
        (duk_c_function) duk_bi_global_object_is_finite,
 
26379
        (duk_c_function) duk_bi_global_object_is_nan,
 
26380
        (duk_c_function) duk_bi_global_object_parse_float,
 
26381
        (duk_c_function) duk_bi_global_object_parse_int,
 
26382
        (duk_c_function) duk_bi_global_object_print,
 
26383
        (duk_c_function) duk_bi_global_object_unescape,
 
26384
        (duk_c_function) duk_bi_json_object_parse,
 
26385
        (duk_c_function) duk_bi_json_object_stringify,
 
26386
        (duk_c_function) duk_bi_logger_constructor,
 
26387
        (duk_c_function) duk_bi_logger_prototype_fmt,
 
26388
        (duk_c_function) duk_bi_logger_prototype_log_shared,
 
26389
        (duk_c_function) duk_bi_logger_prototype_raw,
 
26390
        (duk_c_function) duk_bi_math_object_max,
 
26391
        (duk_c_function) duk_bi_math_object_min,
 
26392
        (duk_c_function) duk_bi_math_object_onearg_shared,
 
26393
        (duk_c_function) duk_bi_math_object_random,
 
26394
        (duk_c_function) duk_bi_math_object_twoarg_shared,
 
26395
        (duk_c_function) duk_bi_number_constructor,
 
26396
        (duk_c_function) duk_bi_number_prototype_to_exponential,
 
26397
        (duk_c_function) duk_bi_number_prototype_to_fixed,
 
26398
        (duk_c_function) duk_bi_number_prototype_to_locale_string,
 
26399
        (duk_c_function) duk_bi_number_prototype_to_precision,
 
26400
        (duk_c_function) duk_bi_number_prototype_to_string,
 
26401
        (duk_c_function) duk_bi_number_prototype_value_of,
 
26402
        (duk_c_function) duk_bi_object_constructor,
 
26403
        (duk_c_function) duk_bi_object_constructor_create,
 
26404
        (duk_c_function) duk_bi_object_constructor_define_properties,
 
26405
        (duk_c_function) duk_bi_object_constructor_define_property,
 
26406
        (duk_c_function) duk_bi_object_constructor_get_own_property_descriptor,
 
26407
        (duk_c_function) duk_bi_object_constructor_get_own_property_names,
 
26408
        (duk_c_function) duk_bi_object_constructor_get_prototype_of,
 
26409
        (duk_c_function) duk_bi_object_constructor_is_extensible,
 
26410
        (duk_c_function) duk_bi_object_constructor_is_sealed_frozen_shared,
 
26411
        (duk_c_function) duk_bi_object_constructor_keys,
 
26412
        (duk_c_function) duk_bi_object_constructor_prevent_extensions,
 
26413
        (duk_c_function) duk_bi_object_constructor_seal_freeze_shared,
 
26414
        (duk_c_function) duk_bi_object_prototype_has_own_property,
 
26415
        (duk_c_function) duk_bi_object_prototype_is_prototype_of,
 
26416
        (duk_c_function) duk_bi_object_prototype_property_is_enumerable,
 
26417
        (duk_c_function) duk_bi_object_prototype_to_locale_string,
 
26418
        (duk_c_function) duk_bi_object_prototype_to_string,
 
26419
        (duk_c_function) duk_bi_object_prototype_value_of,
 
26420
        (duk_c_function) duk_bi_pointer_constructor,
 
26421
        (duk_c_function) duk_bi_pointer_prototype_tostring_shared,
 
26422
        (duk_c_function) duk_bi_regexp_constructor,
 
26423
        (duk_c_function) duk_bi_regexp_prototype_exec,
 
26424
        (duk_c_function) duk_bi_regexp_prototype_test,
 
26425
        (duk_c_function) duk_bi_regexp_prototype_to_string,
 
26426
        (duk_c_function) duk_bi_string_constructor,
 
26427
        (duk_c_function) duk_bi_string_constructor_from_char_code,
 
26428
        (duk_c_function) duk_bi_string_prototype_caseconv_shared,
 
26429
        (duk_c_function) duk_bi_string_prototype_char_at,
 
26430
        (duk_c_function) duk_bi_string_prototype_char_code_at,
 
26431
        (duk_c_function) duk_bi_string_prototype_concat,
 
26432
        (duk_c_function) duk_bi_string_prototype_indexof_shared,
 
26433
        (duk_c_function) duk_bi_string_prototype_locale_compare,
 
26434
        (duk_c_function) duk_bi_string_prototype_match,
 
26435
        (duk_c_function) duk_bi_string_prototype_replace,
 
26436
        (duk_c_function) duk_bi_string_prototype_search,
 
26437
        (duk_c_function) duk_bi_string_prototype_slice,
 
26438
        (duk_c_function) duk_bi_string_prototype_split,
 
26439
        (duk_c_function) duk_bi_string_prototype_substr,
 
26440
        (duk_c_function) duk_bi_string_prototype_substring,
 
26441
        (duk_c_function) duk_bi_string_prototype_to_string,
 
26442
        (duk_c_function) duk_bi_string_prototype_trim,
 
26443
        (duk_c_function) duk_bi_thread_constructor,
 
26444
        (duk_c_function) duk_bi_thread_current,
 
26445
        (duk_c_function) duk_bi_thread_resume,
 
26446
        (duk_c_function) duk_bi_thread_yield,
 
26447
        (duk_c_function) duk_bi_type_error_thrower,
 
26448
};
 
26449
 
 
26450
const duk_uint8_t duk_builtins_data[] = {
 
26451
105,195,74,144,77,40,105,45,9,124,104,46,3,3,72,0,71,225,65,165,168,33,243,
 
26452
6,145,0,122,24,210,150,14,249,35,120,160,55,226,13,76,192,196,177,164,156,
 
26453
22,192,4,202,52,147,197,88,0,169,70,146,120,163,0,23,40,210,79,19,96,3,37,
 
26454
26,73,226,76,0,108,163,73,60,69,128,14,148,105,39,136,48,1,242,144,56,208,
 
26455
254,80,10,26,94,192,63,72,105,18,1,253,1,165,144,5,244,70,148,32,7,202,20,
 
26456
31,255,170,188,128,0,1,240,254,0,0,0,0,93,128,0,1,224,254,0,0,0,0,98,136,
 
26457
19,48,130,70,32,68,198,8,25,0,243,40,28,102,3,76,224,97,160,11,52,162,166,
 
26458
164,80,214,137,155,17,35,106,34,110,68,13,224,81,192,9,56,74,39,25,176,243,
 
26459
146,67,143,81,13,60,36,48,236,144,179,162,66,141,9,9,53,36,32,216,144,115,
 
26460
114,65,142,9,5,63,36,16,248,122,6,102,61,255,255,130,71,134,0,2,135,248,6,
 
26461
192,22,8,255,86,67,249,92,143,213,52,63,21,88,251,84,67,233,116,143,149,
 
26462
210,128,0,190,23,8,247,90,35,217,104,160,0,47,85,146,61,22,201,255,225,0,
 
26463
51,177,136,14,182,16,58,152,192,233,94,35,161,124,142,118,2,10,47,224,0,31,
 
26464
226,0,35,176,200,14,98,244,57,76,79,156,134,7,194,143,248,0,184,64,72,31,
 
26465
227,0,171,176,56,14,176,80,128,0,184,0,143,155,224,164,111,3,1,186,14,124,
 
26466
220,9,3,108,40,13,160,180,54,67,8,216,13,94,107,135,159,53,128,207,192,0,
 
26467
90,160,103,255,255,237,64,67,70,152,33,168,0,11,72,16,212,0,9,162,8,106,0,
 
26468
6,208,4,53,0,4,103,132,31,128,0,179,130,15,255,255,197,39,240,1,102,181,
 
26469
159,7,249,0,146,33,1,148,118,60,129,212,242,6,99,105,25,109,196,112,55,159,
 
26470
53,156,13,26,174,6,160,0,44,167,18,50,92,136,200,115,67,29,208,141,167,84,
 
26471
49,157,144,197,120,67,17,176,12,54,192,48,155,2,0,2,193,108,8,0,11,1,232,
 
26472
11,247,116,10,95,224,0,31,229,2,72,140,19,176,68,32,0,46,161,16,10,111,226,
 
26473
175,160,127,255,247,191,255,255,255,255,175,96,0,0,0,0,0,128,0,0,47,32,0,0,
 
26474
124,63,128,0,0,0,46,160,0,0,120,63,128,0,0,0,46,224,0,0,120,127,128,0,0,0,
 
26475
0,31,230,2,72,128,0,0,0,0,0,0,0,0,51,177,64,142,180,226,58,148,64,185,77,
 
26476
34,225,48,139,116,242,10,127,224,6,182,22,34,212,95,249,104,42,0,255,56,18,
 
26477
68,128,0,15,135,240,0,0,0,11,93,131,161,0,104,89,142,132,0,161,100,58,16,4,
 
26478
135,88,232,64,58,22,35,161,0,168,88,14,132,3,33,28,58,16,6,4,104,232,65,24,
 
26479
145,131,132,117,15,1,94,60,5,112,192,64,2,21,163,0,86,12,4,64,33,86,48,17,
 
26480
0,5,80,192,72,3,21,35,1,32,4,84,12,5,192,33,78,48,23,0,5,48,192,76,2,20,
 
26481
163,1,48,0,82,12,5,0,33,70,48,20,0,5,16,192,84,2,20,35,1,80,0,80,12,5,128,
 
26482
33,62,48,22,0,4,240,200,19,163,100,78,13,20,68,33,54,52,81,16,4,208,210,
 
26483
249,8,66,100,105,124,132,1,48,52,254,98,16,151,26,127,49,0,75,13,79,160,
 
26484
132,37,70,167,208,64,18,131,69,16,8,73,141,20,64,1,36,52,190,64,16,145,26,
 
26485
95,32,0,72,13,63,152,4,163,198,159,204,0,81,99,1,0,24,69,13,20,200,4,84,
 
26486
127,0,0,255,64,98,44,16,48,0,128,161,161,32,128,241,144,177,144,145,144,
 
26487
114,0,0,0,0,0,0,0,0,3,68,51,145,14,208,71,99,72,5,79,240,0,15,244,133,63,
 
26488
144,44,252,64,98,123,149,149,19,92,160,168,152,229,37,64,187,11,0,42,191,
 
26489
128,2,127,168,17,252,162,167,226,3,0,42,255,128,2,127,172,17,252,162,135,
 
26490
226,3,0,43,63,128,2,127,176,17,252,162,103,226,3,0,43,127,128,2,127,180,17,
 
26491
252,162,71,226,3,0,43,191,128,2,127,184,17,252,162,39,226,3,0,43,255,128,2,
 
26492
127,188,17,252,162,7,226,3,0,31,255,144,125,128,21,126,10,128,210,174,41,
 
26493
22,124,129,98,214,4,128,44,171,107,118,123,128,132,93,204,127,222,115,245,
 
26494
252,122,128,142,43,238,127,253,4,86,202,121,128,247,151,182,126,29,202,76,
 
26495
42,120,129,246,66,18,128,48,90,136,168,119,129,61,65,204,127,154,118,254,
 
26496
204,118,129,61,65,236,127,154,118,254,204,145,213,32,135,68,130,128,0,156,
 
26497
210,10,0,4,114,72,40,0,25,197,41,7,4,130,128,2,27,210,10,0,10,110,72,40,0,
 
26498
49,181,32,160,0,230,196,130,128,4,26,209,151,141,72,235,198,148,164,128,0,
 
26499
154,18,64,103,72,40,0,73,153,32,160,1,70,84,130,128,5,153,18,10,0,24,31,
 
26500
255,128,18,217,1,6,52,22,11,255,224,0,31,255,138,51,128,0,129,30,128,0,0,0,
 
26501
0,3,57,128,71,64,4,228,0,29,68,12,137,72,49,38,0,192,124,130,242,66,11,136,
 
26502
199,133,164,67,194,194,17,225,57,1,5,151,240,3,161,63,32,76,250,193,43,224,
 
26503
3,254,64,0,22,127,192,0,63,230,0,39,96,152,64,0,93,66,96,22,159,192,0,63,
 
26504
232,0,39,99,40,64,0,93,76,160,22,191,192,0,63,234,8,57,32,0,0,1,0,0,0,0,0,
 
26505
59,36,19,14,237,251,136,18,33,144,70,138,65,18,32,240,133,16,124,0,4,100,
 
26506
136,62,0,4,32,68,31,0,3,15,162,15,128,2,7,145,7,192,1,83,255,240,143,240,
 
26507
66,226,111,235,139,102,88,188,185,111,228,126,130,47,151,151,45,252,144,
 
26508
105,220,131,47,46,91,249,32,209,135,118,77,154,119,103,0,
 
26509
};
 
26510
#ifdef DUK_USE_INITJS
 
26511
const duk_uint8_t duk_initjs_data[] = {
 
26512
40,102,117,110,99,116,105,111,110,40,99,44,97,41,123,118,97,114,32,98,61,
 
26513
110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,41,59,79,98,106,
 
26514
101,99,116,46,100,101,102,105,110,101,80,114,111,112,101,114,116,121,40,97,
 
26515
46,76,111,103,103,101,114,44,34,99,108,111,103,34,44,123,118,97,108,117,
 
26516
101,58,98,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,109,101,
 
26517
114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,108,101,
 
26518
58,33,48,125,41,125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,
 
26519
59,10,0,
 
26520
};
 
26521
#endif  /* DUK_USE_INITJS */
 
26522
#else
 
26523
#error invalid endianness defines
 
26524
#endif
 
26525
#line 1 "duk_debug_fixedbuffer.c"
 
26526
/*
 
26527
 *  Fixed buffer helper useful for debugging, requires no allocation
 
26528
 *  which is critical for debugging.
 
26529
 */
 
26530
 
 
26531
/* include removed: duk_internal.h */
 
26532
 
 
26533
#ifdef DUK_USE_DEBUG
 
26534
 
 
26535
void duk_fb_put_bytes(duk_fixedbuffer *fb, duk_uint8_t *buffer, duk_uint32_t length) {
 
26536
        duk_uint32_t avail;
 
26537
 
 
26538
        avail = (fb->offset >= fb->length ? (duk_uint32_t) 0 : (duk_uint32_t) (fb->length - fb->offset));
 
26539
        if (length > avail) {
 
26540
                DUK_MEMCPY(fb->buffer + fb->offset, buffer, avail);
 
26541
                fb->offset += avail;
 
26542
                fb->truncated = 1;
 
26543
        } else {
 
26544
                DUK_MEMCPY(fb->buffer + fb->offset, buffer, length);
 
26545
                fb->offset += length;
 
26546
        }
 
26547
}
 
26548
 
 
26549
void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
 
26550
        duk_fb_put_bytes(fb, &x, 1);
 
26551
}
 
26552
 
 
26553
void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
 
26554
        duk_fb_put_bytes(fb, (duk_uint8_t *) x, (duk_uint32_t) DUK_STRLEN(x));
 
26555
}
 
26556
 
 
26557
void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
 
26558
        duk_uint32_t avail;
 
26559
        va_list ap;
 
26560
 
 
26561
        va_start(ap, fmt);
 
26562
        avail = (fb->offset >= fb->length ? (duk_uint32_t) 0 : (duk_uint32_t) (fb->length - fb->offset));
 
26563
        if (avail > 0) {
 
26564
                int res = DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
 
26565
                if (res < 0) {
 
26566
                        /* error */
 
26567
                } else if ((duk_uint32_t) res >= avail) {
 
26568
                        /* (maybe) truncated */
 
26569
                        fb->offset += avail;
 
26570
                        if ((duk_uint32_t) res > avail) {
 
26571
                                /* actual chars dropped (not just NUL term) */
 
26572
                                fb->truncated = 1;
 
26573
                        }
 
26574
                } else {
 
26575
                        /* normal */
 
26576
                        fb->offset += res;
 
26577
                }
 
26578
        }
 
26579
        va_end(ap);
 
26580
}
 
26581
 
 
26582
int duk_fb_is_full(duk_fixedbuffer *fb) {
 
26583
        return (fb->offset >= fb->length);
 
26584
}
 
26585
 
 
26586
#endif  /* DUK_USE_DEBUG */
 
26587
 
 
26588
#line 1 "duk_debug_heap.c"
 
26589
/*
 
26590
 *  Debug dumping of duk_heap.
 
26591
 */
 
26592
 
 
26593
/* include removed: duk_internal.h */
 
26594
 
 
26595
#ifdef DUK_USE_DEBUG
 
26596
 
 
26597
static void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) {
 
26598
        duk_size_t i;
 
26599
        duk_size_t nchars;
 
26600
        duk_size_t maxchars;
 
26601
        duk_uint8_t *data;
 
26602
 
 
26603
        DUK_MEMZERO(buf, buf_size);
 
26604
 
 
26605
        maxchars = (duk_size_t) (buf_size - 1);
 
26606
        data = DUK_HSTRING_GET_DATA(str);
 
26607
        nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars);
 
26608
        for (i = 0; i < nchars; i++) {
 
26609
                char c = (char) data[i];
 
26610
                if (c < 0x20 || c > 0x7e) {
 
26611
                        c = '.';
 
26612
                }
 
26613
                buf[i] = c;
 
26614
        }
 
26615
}
 
26616
 
 
26617
static const char *duk__get_heap_type_string(duk_heaphdr *hdr) {
 
26618
        switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
 
26619
        case DUK_HTYPE_STRING:
 
26620
                return "string";
 
26621
        case DUK_HTYPE_OBJECT:
 
26622
                return "object";
 
26623
        case DUK_HTYPE_BUFFER:
 
26624
                return "buffer";
 
26625
        default:
 
26626
                return "???";
 
26627
        }
 
26628
}
 
26629
 
 
26630
static void duk__dump_indented(duk_heaphdr *obj, int index) {
 
26631
#ifdef DUK_USE_REFERENCE_COUNTING
 
26632
        DUK_DPRINT("  [%d]: %p %s (flags: 0x%08x, ref: %d) -> %!O",
 
26633
                   index,
 
26634
                   (void *) obj,
 
26635
                   duk__get_heap_type_string(obj),
 
26636
                   (int) DUK_HEAPHDR_GET_FLAGS(obj),
 
26637
                   DUK_HEAPHDR_GET_REFCOUNT(obj),
 
26638
                   obj);
 
26639
#else
 
26640
        DUK_DPRINT("  [%d]: %p %s (flags: 0x%08x) -> %!O",
 
26641
                   index,
 
26642
                   (void *) obj,
 
26643
                   duk__get_heap_type_string(obj),
 
26644
                   (int) DUK_HEAPHDR_GET_FLAGS(obj),
 
26645
                   obj);
 
26646
#endif
 
26647
}
 
26648
 
 
26649
static void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) {
 
26650
        int count;
 
26651
        duk_heaphdr *curr;
 
26652
 
 
26653
        DUK_UNREF(heap);
 
26654
 
 
26655
        count = 0;
 
26656
        curr = root;
 
26657
        while (curr) {
 
26658
                count++;
 
26659
                curr = DUK_HEAPHDR_GET_NEXT(curr);
 
26660
        }
 
26661
 
 
26662
        DUK_DPRINT("%s, %d objects", name, count);
 
26663
 
 
26664
        count = 0;
 
26665
        curr = root;
 
26666
        while (curr) {
 
26667
                count++;
 
26668
                duk__dump_indented(curr, count);
 
26669
                curr = DUK_HEAPHDR_GET_NEXT(curr);
 
26670
        }
 
26671
}
 
26672
 
 
26673
static void duk__dump_stringtable(duk_heap *heap) {
 
26674
        duk_uint32_t i;
 
26675
        char buf[64+1];
 
26676
 
 
26677
        DUK_DPRINT("stringtable %p, used %d, size %d, load %d%%",
 
26678
                   (void *) heap->st,
 
26679
                   (int) heap->st_used,
 
26680
                   (int) heap->st_size,
 
26681
                   (int) (((double) heap->st_used) / ((double) heap->st_size) * 100.0));
 
26682
 
 
26683
        for (i = 0; i < heap->st_size; i++) {
 
26684
                duk_hstring *e = heap->st[i];
 
26685
 
 
26686
                if (!e) {
 
26687
                        DUK_DPRINT("  [%d]: NULL", i);
 
26688
                } else if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
 
26689
                        DUK_DPRINT("  [%d]: DELETED", i);
 
26690
                } else {
 
26691
                        duk__sanitize_snippet(buf, sizeof(buf), e);
 
26692
 
 
26693
#ifdef DUK_USE_REFERENCE_COUNTING
 
26694
                        DUK_DPRINT("  [%d]: %p (flags: 0x%08x, ref: %d) '%s', strhash=0x%08x, blen=%d, clen=%d, "
 
26695
                                   "arridx=%d, internal=%d, reserved_word=%d, strict_reserved_word=%d, eval_or_arguments=%d",
 
26696
                                   i,
 
26697
                                   (void *) e,
 
26698
                                   (int) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
 
26699
                                   (int) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) e),
 
26700
                                   buf,
 
26701
                                   (int) e->hash,
 
26702
                                   (int) e->blen,
 
26703
                                   (int) e->clen,
 
26704
                                   DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0,
 
26705
                                   DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0,
 
26706
                                   DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0,
 
26707
                                   DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0,
 
26708
                                   DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0);
 
26709
#else
 
26710
                        DUK_DPRINT("  [%d]: %p (flags: 0x%08x) '%s', strhash=0x%08x, blen=%d, clen=%d, "
 
26711
                                   "arridx=%d, internal=%d, reserved_word=%d, strict_reserved_word=%d, eval_or_arguments=%d",
 
26712
                                   i,
 
26713
                                   (void *) e,
 
26714
                                   (int) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
 
26715
                                   buf,
 
26716
                                   (int) e->hash,
 
26717
                                   (int) e->blen,
 
26718
                                   (int) e->clen,
 
26719
                                   DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0,
 
26720
                                   DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0,
 
26721
                                   DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0,
 
26722
                                   DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0,
 
26723
                                   DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0);
 
26724
#endif
 
26725
                }
 
26726
        }
 
26727
}
 
26728
 
 
26729
static void duk__dump_strcache(duk_heap *heap) {
 
26730
        duk_uint32_t i;
 
26731
        char buf[64+1];
 
26732
 
 
26733
        DUK_DPRINT("stringcache");
 
26734
 
 
26735
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
26736
                duk_strcache *c = &heap->strcache[i];
 
26737
                if (!c->h) {
 
26738
                        DUK_DPRINT("  [%d]: bidx=%d, cidx=%d, str=NULL",
 
26739
                                   i, c->bidx, c->cidx);
 
26740
                } else {
 
26741
                        duk__sanitize_snippet(buf, sizeof(buf), c->h);
 
26742
                        DUK_DPRINT("  [%d]: bidx=%d cidx=%d str=%s",
 
26743
                                   i, c->bidx, c->cidx, buf);
 
26744
                }
 
26745
        } 
 
26746
}
 
26747
 
 
26748
void duk_debug_dump_heap(duk_heap *heap) {
 
26749
        char buf[64+1];
 
26750
 
 
26751
        DUK_DPRINT("=== heap %p ===", (void *) heap);
 
26752
        DUK_DPRINT("  flags: 0x%08x", (int) heap->flags);
 
26753
 
 
26754
        /* Note: there is no standard formatter for function pointers */
 
26755
#ifdef DUK_USE_GCC_PRAGMAS
 
26756
#pragma GCC diagnostic push
 
26757
#pragma GCC diagnostic ignored "-pedantic"
 
26758
#endif
 
26759
        duk_debug_format_funcptr(buf, sizeof(buf), (unsigned char *) &heap->alloc_func, sizeof(heap->alloc_func));
 
26760
        DUK_DPRINT("  alloc_func: %s", buf);
 
26761
        duk_debug_format_funcptr(buf, sizeof(buf), (unsigned char *) &heap->realloc_func, sizeof(heap->realloc_func));
 
26762
        DUK_DPRINT("  realloc_func: %s", buf);
 
26763
        duk_debug_format_funcptr(buf, sizeof(buf), (unsigned char *) &heap->free_func, sizeof(heap->free_func));
 
26764
        DUK_DPRINT("  free_func: %s", buf);
 
26765
        duk_debug_format_funcptr(buf, sizeof(buf), (unsigned char *) &heap->fatal_func, sizeof(heap->fatal_func));
 
26766
        DUK_DPRINT("  fatal_func: %s", buf);
 
26767
#ifdef DUK_USE_GCC_PRAGMAS
 
26768
#pragma GCC diagnostic pop
 
26769
#endif
 
26770
 
 
26771
        DUK_DPRINT("  alloc_udata: %p", (void *) heap->alloc_udata);
 
26772
 
 
26773
#ifdef DUK_USE_MARK_AND_SWEEP
 
26774
#ifdef DUK_USE_VOLUNTARY_GC
 
26775
        DUK_DPRINT("  mark-and-sweep trig counter: %d", heap->mark_and_sweep_trigger_counter);
 
26776
#endif
 
26777
        DUK_DPRINT("  mark-and-sweep rec depth: %d", heap->mark_and_sweep_recursion_depth);
 
26778
        DUK_DPRINT("  mark-and-sweep base flags: 0x%08x", heap->mark_and_sweep_base_flags);
 
26779
#endif
 
26780
 
 
26781
        DUK_DPRINT("  lj.jmpbuf_ptr: %p", (void *) heap->lj.jmpbuf_ptr);
 
26782
        DUK_DPRINT("  lj.type: %d", heap->lj.type);
 
26783
        DUK_DPRINT("  lj.value1: %!T", &heap->lj.value1);
 
26784
        DUK_DPRINT("  lj.value2: %!T", &heap->lj.value2);
 
26785
        DUK_DPRINT("  lj.iserror: %d", heap->lj.iserror);
 
26786
 
 
26787
        DUK_DPRINT("  handling_error: %d", heap->handling_error);
 
26788
 
 
26789
        DUK_DPRINT("  heap_thread: %!@O", (duk_heaphdr *) heap->heap_thread);
 
26790
        DUK_DPRINT("  curr_thread: %!@O", (duk_heaphdr *) heap->curr_thread);
 
26791
        DUK_DPRINT("  heap_object: %!@O", (duk_heaphdr *) heap->heap_object);
 
26792
 
 
26793
        DUK_DPRINT("  call_recursion_depth: %d", heap->call_recursion_depth);
 
26794
        DUK_DPRINT("  call_recursion_limit: %d", heap->call_recursion_limit);
 
26795
 
 
26796
        DUK_DPRINT("  hash_seed: 0x%08x", (int) heap->hash_seed);
 
26797
        DUK_DPRINT("  rnd_state: 0x%08x", (int) heap->rnd_state);
 
26798
 
 
26799
        duk__dump_strcache(heap);
 
26800
 
 
26801
        duk__dump_heaphdr_list(heap, heap->heap_allocated, "heap allocated");
 
26802
 
 
26803
#ifdef DUK_USE_REFERENCE_COUNTING
 
26804
        duk__dump_heaphdr_list(heap, heap->refzero_list, "refcounting refzero list");
 
26805
#endif
 
26806
 
 
26807
#ifdef DUK_USE_MARK_AND_SWEEP
 
26808
        duk__dump_heaphdr_list(heap, heap->finalize_list, "mark-and-sweep finalize list");
 
26809
#endif
 
26810
 
 
26811
        duk__dump_stringtable(heap);
 
26812
 
 
26813
        /* heap->strs: not worth dumping */
 
26814
}
 
26815
 
 
26816
#endif  /* DUK_USE_DEBUG */
 
26817
 
 
26818
#line 1 "duk_debug_hobject.c"
 
26819
/*
 
26820
 *  Debug dumping of duk_hobject.
 
26821
 */
 
26822
 
 
26823
/* include removed: duk_internal.h */
 
26824
 
 
26825
#ifdef DUK_USE_DEBUG
 
26826
 
 
26827
/* must match duk_hobject.h */
 
26828
static const char *duk__class_names[32] = {
 
26829
        "unused",
 
26830
        "Arguments",
 
26831
        "Array",
 
26832
        "Boolean",
 
26833
        "Date",
 
26834
        "Error",
 
26835
        "Function",
 
26836
        "JSON",
 
26837
        "Math",
 
26838
        "Number",
 
26839
        "Object",
 
26840
        "RegExp",
 
26841
        "String",
 
26842
        "global",
 
26843
        "ObjEnv",
 
26844
        "DecEnv",
 
26845
        "Buffer",
 
26846
        "Pointer",
 
26847
        "unused",
 
26848
        "unused",
 
26849
        "unused",
 
26850
        "unused",
 
26851
        "unused",
 
26852
        "unused",
 
26853
        "unused",
 
26854
        "unused",
 
26855
        "unused",
 
26856
        "unused",
 
26857
        "unused",
 
26858
        "unused",
 
26859
        "unused",
 
26860
        "unused",
 
26861
};
 
26862
 
 
26863
/* for thread dumping */
 
26864
static char duk__get_act_summary_char(duk_activation *act) {
 
26865
        if (act->func) {
 
26866
                if (DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
 
26867
                        return 'c';
 
26868
                } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(act->func)) {
 
26869
                        return 'n';
 
26870
                } else {
 
26871
                        /* should not happen */
 
26872
                        return '?';
 
26873
                }
 
26874
        } else {
 
26875
                /* should not happen */
 
26876
                return '?';
 
26877
        }
 
26878
}
 
26879
 
 
26880
/* for thread dumping */
 
26881
static char duk__get_tval_summary_char(duk_tval *tv) {
 
26882
        switch (DUK_TVAL_GET_TAG(tv)) {
 
26883
        case DUK_TAG_UNDEFINED:
 
26884
                if (DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
26885
                        return '.';
 
26886
                }
 
26887
                return 'u';
 
26888
        case DUK_TAG_NULL:
 
26889
                return 'n';
 
26890
        case DUK_TAG_BOOLEAN:
 
26891
                return 'b';
 
26892
        case DUK_TAG_STRING:
 
26893
                return 's';
 
26894
        case DUK_TAG_OBJECT: {
 
26895
                duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
 
26896
 
 
26897
                if (DUK_HOBJECT_IS_ARRAY(h)) {
 
26898
                        return 'A';
 
26899
                } else if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
26900
                        return 'C';
 
26901
                } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
26902
                        return 'N';
 
26903
                } else if (DUK_HOBJECT_IS_THREAD(h)) {
 
26904
                        return 'T';
 
26905
                }
 
26906
                return 'O';
 
26907
        }
 
26908
        case DUK_TAG_BUFFER: {
 
26909
                return 'B';
 
26910
        }
 
26911
        case DUK_TAG_POINTER: {
 
26912
                return 'P';
 
26913
        }
 
26914
        default:
 
26915
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
26916
                return 'd';
 
26917
        }
 
26918
 
 
26919
        DUK_UNREACHABLE();
 
26920
}
 
26921
 
 
26922
/* for thread dumping */
 
26923
static char duk__get_cat_summary_char(duk_catcher *catcher) {
 
26924
        switch (DUK_CAT_GET_TYPE(catcher)) {
 
26925
        case DUK_CAT_TYPE_TCF:
 
26926
                if (DUK_CAT_HAS_CATCH_ENABLED(catcher)) {
 
26927
                        if (DUK_CAT_HAS_FINALLY_ENABLED(catcher)) {
 
26928
                                return 'C';  /* catch and finally active */
 
26929
                        } else {
 
26930
                                return 'c';  /* only catch active */
 
26931
                        }
 
26932
                } else {
 
26933
                        if (DUK_CAT_HAS_FINALLY_ENABLED(catcher)) {
 
26934
                                return 'f';  /* only finally active */
 
26935
                        } else {
 
26936
                                return 'w';  /* neither active (usually 'with') */
 
26937
                        }
 
26938
                }
 
26939
        case DUK_CAT_TYPE_LABEL:
 
26940
                return 'l';
 
26941
        case DUK_CAT_TYPE_UNKNOWN:
 
26942
        default:
 
26943
                return '?';
 
26944
        }
 
26945
 
 
26946
        DUK_UNREACHABLE();
 
26947
}
 
26948
 
 
26949
void duk_debug_dump_hobject(duk_hobject *obj) {
 
26950
        duk_uint_fast32_t i;
 
26951
        const char *str_empty = "";
 
26952
        const char *str_excl = "!";
 
26953
 
 
26954
        DUK_DPRINT("=== hobject %p ===", (void *) obj);
 
26955
        if (!obj) {
 
26956
                return;
 
26957
        }
 
26958
 
 
26959
        DUK_DPRINT("  %sextensible", DUK_HOBJECT_HAS_EXTENSIBLE(obj) ? str_empty : str_excl);
 
26960
        DUK_DPRINT("  %sconstructable", DUK_HOBJECT_HAS_CONSTRUCTABLE(obj) ? str_empty : str_excl);
 
26961
        DUK_DPRINT("  %sbound", DUK_HOBJECT_HAS_BOUND(obj) ? str_empty : str_excl);
 
26962
        DUK_DPRINT("  %scompiledfunction", DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj) ? str_empty : str_excl);
 
26963
        DUK_DPRINT("  %snativefunction", DUK_HOBJECT_HAS_NATIVEFUNCTION(obj) ? str_empty : str_excl);
 
26964
        DUK_DPRINT("  %sthread", DUK_HOBJECT_HAS_THREAD(obj) ? str_empty : str_excl);
 
26965
        DUK_DPRINT("  %sarray_part", DUK_HOBJECT_HAS_ARRAY_PART(obj) ? str_empty : str_excl);
 
26966
        DUK_DPRINT("  %sstrict", DUK_HOBJECT_HAS_STRICT(obj) ? str_empty : str_excl);
 
26967
        DUK_DPRINT("  %snewenv", DUK_HOBJECT_HAS_NEWENV(obj) ? str_empty : str_excl);
 
26968
        DUK_DPRINT("  %snamebinding", DUK_HOBJECT_HAS_NAMEBINDING(obj) ? str_empty : str_excl);
 
26969
        DUK_DPRINT("  %screateargs", DUK_HOBJECT_HAS_CREATEARGS(obj) ? str_empty : str_excl);
 
26970
        DUK_DPRINT("  %senvrecclosed", DUK_HOBJECT_HAS_ENVRECCLOSED(obj) ? str_empty : str_excl);
 
26971
        DUK_DPRINT("  %sspecial_array", DUK_HOBJECT_HAS_SPECIAL_ARRAY(obj) ? str_empty : str_excl);
 
26972
        DUK_DPRINT("  %sspecial_stringobj", DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj) ? str_empty : str_excl);
 
26973
        DUK_DPRINT("  %sspecial_arguments", DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj) ? str_empty : str_excl);
 
26974
 
 
26975
        DUK_DPRINT("  class: number %d -> %s",
 
26976
                   (int) DUK_HOBJECT_GET_CLASS_NUMBER(obj),
 
26977
                   duk__class_names[(DUK_HOBJECT_GET_CLASS_NUMBER(obj)) & ((1 << DUK_HOBJECT_FLAG_CLASS_BITS) - 1)]);
 
26978
 
 
26979
        DUK_DPRINT("  prototype: %p -> %!O",
 
26980
                   (void *) obj->prototype,
 
26981
                   (duk_heaphdr *) obj->prototype);
 
26982
 
 
26983
        DUK_DPRINT("  props: p=%p, e_size=%d, e_used=%d, a_size=%d, h_size=%d",
 
26984
                   (void *) obj->p,
 
26985
                   (int) obj->e_size,
 
26986
                   (int) obj->e_used,
 
26987
                   (int) obj->a_size,
 
26988
                   (int) obj->h_size);
 
26989
 
 
26990
        /*
 
26991
         *  Object (struct layout) specific dumping.  Inline code here
 
26992
         *  instead of helpers, to ensure debug line prefix is identical.
 
26993
         */
 
26994
 
 
26995
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(obj)) {
 
26996
                duk_hcompiledfunction *h = (duk_hcompiledfunction *) obj;
 
26997
 
 
26998
                DUK_DPRINT("  hcompiledfunction");
 
26999
                DUK_DPRINT("  data: %!O", h->data);
 
27000
                DUK_DPRINT("  nregs: %d", (int) h->nregs);
 
27001
                DUK_DPRINT("  nargs: %d", (int) h->nargs);
 
27002
 
 
27003
                if (h->data && DUK_HBUFFER_HAS_DYNAMIC(h->data) && DUK_HBUFFER_GET_DATA_PTR(h->data)) {
 
27004
                        DUK_DPRINT("  consts: %p (%d, %d bytes)",
 
27005
                                   (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(h),
 
27006
                                   (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(h),
 
27007
                                   (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(h));
 
27008
                        DUK_DPRINT("  funcs: %p (%d, %d bytes)",
 
27009
                                   (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(h),
 
27010
                                   (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(h),
 
27011
                                   (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(h));
 
27012
                        DUK_DPRINT("  bytecode: %p (%d, %d bytes)",
 
27013
                                   (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(h),
 
27014
                                   (int) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(h),
 
27015
                                   (int) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(h));
 
27016
                } else {
 
27017
                        DUK_DPRINT("  consts: ???");
 
27018
                        DUK_DPRINT("  funcs: ???");
 
27019
                        DUK_DPRINT("  bytecode: ???");
 
27020
                }
 
27021
        } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj)) {
 
27022
                duk_hnativefunction *h = (duk_hnativefunction *) obj;
 
27023
 
 
27024
                DUK_DPRINT("  hnativefunction");
 
27025
                /* XXX: h->func, cannot print function pointers portably */
 
27026
                DUK_DPRINT("  nargs: %d", (int) h->nargs);
 
27027
        } else if (DUK_HOBJECT_IS_THREAD(obj)) {
 
27028
                duk_hthread *thr = (duk_hthread *) obj;
 
27029
                duk_tval *p;
 
27030
 
 
27031
                DUK_DPRINT("  hthread");
 
27032
                DUK_DPRINT("  strict: %d", (int) thr->strict);
 
27033
                DUK_DPRINT("  state: %d", (int) thr->state);
 
27034
 
 
27035
                DUK_DPRINT("  valstack_max: %d, callstack_max:%d, catchstack_max: %d",
 
27036
                           thr->valstack_max, thr->callstack_max, thr->catchstack_max);
 
27037
 
 
27038
                DUK_DPRINT("  callstack: ptr %p, size %d, top %d, preventcount %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
 
27039
                           (void *) thr->callstack,
 
27040
                           thr->callstack_size,
 
27041
                           thr->callstack_top,
 
27042
                           thr->callstack_preventcount,
 
27043
                           thr->callstack_top,
 
27044
                           thr->callstack_top * sizeof(duk_activation),
 
27045
                           thr->callstack_size,
 
27046
                           thr->callstack_size * sizeof(duk_activation));
 
27047
 
 
27048
                DUK_DEBUG_SUMMARY_INIT();
 
27049
                DUK_DEBUG_SUMMARY_CHAR('[');
 
27050
                for (i = 0; i <= thr->callstack_size; i++) {
 
27051
                        if (i == thr->callstack_top) {
 
27052
                                DUK_DEBUG_SUMMARY_CHAR('|');
 
27053
                        }
 
27054
                        if (!thr->callstack) {
 
27055
                                DUK_DEBUG_SUMMARY_CHAR('@');
 
27056
                        } else if (i < thr->callstack_size) {
 
27057
                                if (i < thr->callstack_top) {
 
27058
                                        /* tailcalling is nice to see immediately; other flags (e.g. strict)
 
27059
                                         * not that important.
 
27060
                                         */
 
27061
                                        if (thr->callstack[i].flags & DUK_ACT_FLAG_TAILCALLED) {
 
27062
                                                DUK_DEBUG_SUMMARY_CHAR('/');
 
27063
                                        }
 
27064
                                        DUK_DEBUG_SUMMARY_CHAR(duk__get_act_summary_char(&thr->callstack[i]));
 
27065
                                } else {
 
27066
                                        DUK_DEBUG_SUMMARY_CHAR('.');
 
27067
                                }
 
27068
                        }
 
27069
                }
 
27070
                DUK_DEBUG_SUMMARY_CHAR(']');
 
27071
                DUK_DEBUG_SUMMARY_FINISH();
 
27072
 
 
27073
                DUK_DPRINT("  valstack: ptr %p, end %p (%d), bottom %p (%d), top %p (%d), used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
 
27074
                           (void *) thr->valstack,
 
27075
                           (void *) thr->valstack_end,
 
27076
                           (int) (thr->valstack_end - thr->valstack),
 
27077
                           (void *) thr->valstack_bottom,
 
27078
                           (int) (thr->valstack_bottom - thr->valstack),
 
27079
                           (void *) thr->valstack_top,
 
27080
                           (int) (thr->valstack_top - thr->valstack),
 
27081
                           (int) (thr->valstack_top - thr->valstack),
 
27082
                           (int) (thr->valstack_top - thr->valstack) * sizeof(duk_tval),
 
27083
                           (int) (thr->valstack_end - thr->valstack),
 
27084
                           (int) (thr->valstack_end - thr->valstack) * sizeof(duk_tval));
 
27085
 
 
27086
                DUK_DEBUG_SUMMARY_INIT();
 
27087
                DUK_DEBUG_SUMMARY_CHAR('[');
 
27088
                p = thr->valstack;
 
27089
                while (p <= thr->valstack_end) {
 
27090
                        i = (duk_uint_fast32_t) (p - thr->valstack);
 
27091
                        if (thr->callstack &&
 
27092
                            thr->callstack_top > 0 &&
 
27093
                            i == (duk_size_t) (thr->callstack + thr->callstack_top - 1)->idx_bottom) {
 
27094
                                DUK_DEBUG_SUMMARY_CHAR('>');
 
27095
                        }
 
27096
                        if (p == thr->valstack_top) {
 
27097
                                DUK_DEBUG_SUMMARY_CHAR('|');
 
27098
                        }
 
27099
                        if (p < thr->valstack_end) {
 
27100
                                if (p < thr->valstack_top) {
 
27101
                                        DUK_DEBUG_SUMMARY_CHAR(duk__get_tval_summary_char(p));
 
27102
                                } else {
 
27103
                                        /* XXX: safe printer for these?  would be nice, because
 
27104
                                         * we could visualize whether the values are in proper
 
27105
                                         * state.
 
27106
                                         */
 
27107
                                        DUK_DEBUG_SUMMARY_CHAR('.');
 
27108
                                }
 
27109
                        }
 
27110
                        p++;
 
27111
                }
 
27112
                DUK_DEBUG_SUMMARY_CHAR(']');
 
27113
                DUK_DEBUG_SUMMARY_FINISH();
 
27114
 
 
27115
                DUK_DPRINT("  catchstack: ptr %p, size %d, top %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
 
27116
                           (void *) thr->catchstack,
 
27117
                           thr->catchstack_size,
 
27118
                           thr->catchstack_top,
 
27119
                           thr->catchstack_top,
 
27120
                           thr->catchstack_top * sizeof(duk_catcher),
 
27121
                           thr->catchstack_size,
 
27122
                           thr->catchstack_size * sizeof(duk_catcher));
 
27123
 
 
27124
                DUK_DEBUG_SUMMARY_INIT();
 
27125
                DUK_DEBUG_SUMMARY_CHAR('[');
 
27126
                for (i = 0; i <= thr->catchstack_size; i++) {
 
27127
                        if (i == thr->catchstack_top) {
 
27128
                                DUK_DEBUG_SUMMARY_CHAR('|');
 
27129
                        }
 
27130
                        if (!thr->catchstack) {
 
27131
                                DUK_DEBUG_SUMMARY_CHAR('@');
 
27132
                        } else if (i < thr->catchstack_size) {
 
27133
                                if (i < thr->catchstack_top) {
 
27134
                                        DUK_DEBUG_SUMMARY_CHAR(duk__get_cat_summary_char(&thr->catchstack[i]));
 
27135
                                } else {
 
27136
                                        DUK_DEBUG_SUMMARY_CHAR('.');
 
27137
                                }
 
27138
                        }
 
27139
                }
 
27140
                DUK_DEBUG_SUMMARY_CHAR(']');
 
27141
                DUK_DEBUG_SUMMARY_FINISH();
 
27142
 
 
27143
                DUK_DPRINT("  resumer: ptr %p",
 
27144
                           (void *) thr->resumer);
 
27145
 
 
27146
#if 0  /* worth dumping? */
 
27147
                for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
27148
                        DUK_DPRINT("  builtins[%d] -> %!@O", i, thr->builtins[i]);
 
27149
                }
 
27150
#endif
 
27151
        }
 
27152
 
 
27153
        if (obj->p) {
 
27154
                DUK_DPRINT("  props alloc size: %d",
 
27155
                           (int) DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size));
 
27156
        } else {
 
27157
                DUK_DPRINT("  props alloc size: n/a");
 
27158
        }
 
27159
 
 
27160
        DUK_DPRINT("  prop entries:");
 
27161
        for (i = 0; i < obj->e_size; i++) {
 
27162
                duk_hstring *k;
 
27163
                duk_propvalue *v;
 
27164
 
 
27165
                k = DUK_HOBJECT_E_GET_KEY(obj, i);
 
27166
                v = DUK_HOBJECT_E_GET_VALUE_PTR(obj, i);
 
27167
 
 
27168
                if (i >= obj->e_used) {
 
27169
                        DUK_DPRINT("    [%d]: UNUSED", i);
 
27170
                        continue;
 
27171
                }
 
27172
 
 
27173
                if (!k) {
 
27174
                        DUK_DPRINT("    [%d]: NULL", i);
 
27175
                        continue;
 
27176
                }
 
27177
 
 
27178
                if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i)) {
 
27179
                        DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %!O -> get:%p set:%p; get %!O; set %!O",
 
27180
                                   i,
 
27181
                                   DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i),
 
27182
                                   DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i),
 
27183
                                   DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i),
 
27184
                                   DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i),
 
27185
                                   k,
 
27186
                                   (void *) v->a.get,
 
27187
                                   (void *) v->a.set,
 
27188
                                   (duk_heaphdr *) v->a.get,
 
27189
                                   (duk_heaphdr *) v->a.set);
 
27190
                } else {
 
27191
                        DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %!O -> %!T",
 
27192
                                   i,
 
27193
                                   DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i),
 
27194
                                   DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i),
 
27195
                                   DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i),
 
27196
                                   DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i),
 
27197
                                   k,
 
27198
                                   &v->v);
 
27199
                }
 
27200
        }
 
27201
 
 
27202
        DUK_DPRINT("  array entries:");
 
27203
        for (i = 0; i < obj->a_size; i++) {
 
27204
                DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %d -> %!T",
 
27205
                           i,
 
27206
                           1,  /* implicit attributes */
 
27207
                           1,
 
27208
                           1,
 
27209
                           0,
 
27210
                           i,
 
27211
                           DUK_HOBJECT_A_GET_VALUE_PTR(obj, i));
 
27212
        }
 
27213
 
 
27214
        DUK_DPRINT("  hash entries:");
 
27215
        for (i = 0; i < obj->h_size; i++) {
 
27216
                duk_uint32_t t = DUK_HOBJECT_H_GET_INDEX(obj, i);
 
27217
                if (t == DUK_HOBJECT_HASHIDX_UNUSED) {
 
27218
                        DUK_DPRINT("    [%d]: unused", i);
 
27219
                } else if (t == DUK_HOBJECT_HASHIDX_DELETED) {
 
27220
                        DUK_DPRINT("    [%d]: deleted", i);
 
27221
                } else {
 
27222
                        DUK_DPRINT("    [%d]: %d",
 
27223
                                   i,
 
27224
                                   (int) t);
 
27225
                }
 
27226
        }
 
27227
}
 
27228
 
 
27229
void duk_debug_dump_callstack(duk_hthread *thr) {
 
27230
        duk_uint_fast32_t i;
 
27231
 
 
27232
        DUK_DPRINT("=== hthread %p callstack: %d entries ===",
 
27233
                   (void *) thr,
 
27234
                   (thr == NULL ? 0 : thr->callstack_top));
 
27235
        if (!thr) {
 
27236
                return;
 
27237
        }
 
27238
 
 
27239
        for (i = 0; i < thr->callstack_top; i++) {
 
27240
                duk_activation *act = &thr->callstack[i];
 
27241
                duk_tval *this_binding = NULL;
 
27242
 
 
27243
                this_binding = thr->valstack + act->idx_bottom - 1;
 
27244
                if (this_binding < thr->valstack || this_binding >= thr->valstack_top) {
 
27245
                        this_binding = NULL;
 
27246
                }
 
27247
 
 
27248
                DUK_DPRINT("  [%d] -> flags=0x%08x, func=%!O, var_env=%!iO, lex_env=%!iO, pc=%d, idx_bottom=%d, idx_retval=%d, this_binding=%!T",
 
27249
                           i,
 
27250
                           act->flags,
 
27251
                           (duk_heaphdr *) act->func,
 
27252
                           (duk_heaphdr *) act->var_env,
 
27253
                           (duk_heaphdr *) act->lex_env,
 
27254
                           act->pc,
 
27255
                           act->idx_bottom,
 
27256
                           act->idx_retval,
 
27257
                           this_binding);
 
27258
        }
 
27259
}
 
27260
 
 
27261
void duk_debug_dump_activation(duk_hthread *thr, duk_activation *act) {
 
27262
        if (!act) {
 
27263
                DUK_DPRINT("duk_activation: NULL");
 
27264
        } else {
 
27265
                duk_tval *this_binding = NULL;
 
27266
 
 
27267
                this_binding = thr->valstack + act->idx_bottom - 1;
 
27268
                if (this_binding < thr->valstack || this_binding >= thr->valstack_top) {
 
27269
                        this_binding = NULL;
 
27270
                }
 
27271
 
 
27272
                DUK_DPRINT("duk_activation: %p -> flags=0x%08x, func=%!O, var_env=%!O, lex_env=%!O, pc=%d, idx_bottom=%d, idx_retval=%d, this_binding=%!T",
 
27273
                           (void *) act,
 
27274
                           act->flags,
 
27275
                           (duk_heaphdr *) act->func,
 
27276
                           (duk_heaphdr *) act->var_env,
 
27277
                           (duk_heaphdr *) act->lex_env,
 
27278
                           act->pc,
 
27279
                           act->idx_bottom,
 
27280
                           act->idx_retval,
 
27281
                           this_binding);
 
27282
        }
 
27283
}
 
27284
 
 
27285
#endif  /* DUK_USE_DEBUG */
 
27286
 
 
27287
#line 1 "duk_debug_macros.c"
 
27288
/*
 
27289
 *  Debugging macro calls.
 
27290
 */
 
27291
 
 
27292
/* include removed: duk_internal.h */
 
27293
 
 
27294
#ifdef DUK_USE_DEBUG
 
27295
 
 
27296
/*
 
27297
 *  Debugging enabled
 
27298
 */
 
27299
 
 
27300
#include <stdio.h>
 
27301
#include <stdlib.h>
 
27302
#include <stdarg.h>
 
27303
 
 
27304
/* for one-char summaries (usable for e.g. valstack) */
 
27305
char duk_debug_summary_buf[DUK_DEBUG_SUMMARY_BUF_SIZE];
 
27306
int duk_debug_summary_idx;
 
27307
 
 
27308
#define DUK__DEBUG_BUFSIZE  DUK_USE_DEBUG_BUFSIZE
 
27309
static char duk__debug_buf[DUK__DEBUG_BUFSIZE];
 
27310
 
 
27311
static const char *duk__get_level_string(int level) {
 
27312
        switch (level) {
 
27313
        case DUK_LEVEL_DEBUG:
 
27314
                return "D";
 
27315
        case DUK_LEVEL_DDEBUG:
 
27316
                return "DD";
 
27317
        case DUK_LEVEL_DDDEBUG:
 
27318
                return "DDD";
 
27319
        }
 
27320
        return "???";
 
27321
}
 
27322
 
 
27323
#ifdef DUK_USE_DPRINT_COLORS
 
27324
 
 
27325
/* http://en.wikipedia.org/wiki/ANSI_escape_code */
 
27326
#define DUK__TERM_REVERSE  "\x1b[7m"
 
27327
#define DUK__TERM_BRIGHT   "\x1b[1m"
 
27328
#define DUK__TERM_RESET    "\x1b[0m"
 
27329
#define DUK__TERM_BLUE     "\x1b[34m"
 
27330
#define DUK__TERM_RED      "\x1b[31m"
 
27331
 
 
27332
static const char *duk__get_term_1(int level) {
 
27333
        DUK_UNREF(level);
 
27334
        return (const char *) DUK__TERM_RED;
 
27335
}
 
27336
 
 
27337
static const char *duk__get_term_2(int level) {
 
27338
        switch (level) {
 
27339
        case DUK_LEVEL_DEBUG:
 
27340
                return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
 
27341
        case DUK_LEVEL_DDEBUG:
 
27342
                return (const char *) (DUK__TERM_RESET);
 
27343
        case DUK_LEVEL_DDDEBUG:
 
27344
                return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
 
27345
        }
 
27346
        return (const char *) DUK__TERM_RESET;
 
27347
}
 
27348
 
 
27349
static const char *duk__get_term_3(int level) {
 
27350
        DUK_UNREF(level);
 
27351
        return (const char *) DUK__TERM_RESET;
 
27352
}
 
27353
 
 
27354
#else
 
27355
 
 
27356
static const char *duk__get_term_1(int level) {
 
27357
        DUK_UNREF(level);
 
27358
        return (const char *) "";
 
27359
}
 
27360
 
 
27361
static const char *duk__get_term_2(int level) {
 
27362
        DUK_UNREF(level);
 
27363
        return (const char *) "";
 
27364
}
 
27365
 
 
27366
static const char *duk__get_term_3(int level) {
 
27367
        DUK_UNREF(level);
 
27368
        return (const char *) "";
 
27369
}
 
27370
 
 
27371
#endif  /* DUK_USE_DPRINT_COLORS */
 
27372
 
 
27373
#ifdef DUK_USE_VARIADIC_MACROS
 
27374
 
 
27375
void duk_debug_log(int level, const char *file, int line, const char *func, char *fmt, ...) {
 
27376
        va_list ap;
 
27377
 
 
27378
        va_start(ap, fmt);
 
27379
 
 
27380
        DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
 
27381
        duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
 
27382
 
 
27383
#ifdef DUK_USE_DPRINT_RDTSC
 
27384
        DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%d (%s):%s %s%s\n",
 
27385
                    duk__get_term_1(level),
 
27386
                    duk__get_level_string(level),
 
27387
                    duk_rdtsc(),
 
27388
                    file,
 
27389
                    line,
 
27390
                    func,
 
27391
                    duk__get_term_2(level),
 
27392
                    duk__debug_buf,
 
27393
                    duk__get_term_3(level));
 
27394
#else
 
27395
        DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%d (%s):%s %s%s\n",
 
27396
                    duk__get_term_1(level),
 
27397
                    duk__get_level_string(level),
 
27398
                    file,
 
27399
                    line,
 
27400
                    func,
 
27401
                    duk__get_term_2(level),
 
27402
                    duk__debug_buf,
 
27403
                    duk__get_term_3(level));
 
27404
#endif
 
27405
        DUK_FFLUSH(DUK_STDERR);
 
27406
 
 
27407
        va_end(ap);
 
27408
}
 
27409
 
 
27410
#else  /* DUK_USE_VARIADIC_MACROS */
 
27411
 
 
27412
char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
 
27413
char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
 
27414
char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
 
27415
int duk_debug_level_stash;
 
27416
 
 
27417
void duk_debug_log(char *fmt, ...) {
 
27418
        va_list ap;
 
27419
        int level = duk_debug_level_stash;
 
27420
 
 
27421
        va_start(ap, fmt);
 
27422
 
 
27423
        DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
 
27424
        duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
 
27425
 
 
27426
#ifdef DUK_USE_DPRINT_RDTSC
 
27427
        DUK_FPRINTF(DUK_STDERR, "%s[%s] <%llu> %s:%s (%s):%s %s%s\n",
 
27428
                    duk__get_term_1(level),
 
27429
                    duk__get_level_string(duk_debug_level_stash),
 
27430
                    duk_rdtsc(),
 
27431
                    duk_debug_file_stash,
 
27432
                    duk_debug_line_stash,
 
27433
                    duk_debug_func_stash,
 
27434
                    duk__get_term_2(level),
 
27435
                    duk__debug_buf,
 
27436
                    duk__get_term_3(level));
 
27437
#else
 
27438
        DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
 
27439
                    duk__get_term_1(level),
 
27440
                    duk__get_level_string(duk_debug_level_stash),
 
27441
                    duk_debug_file_stash,
 
27442
                    duk_debug_line_stash,
 
27443
                    duk_debug_func_stash,
 
27444
                    duk__get_term_2(level),
 
27445
                    duk__debug_buf,
 
27446
                    duk__get_term_3(level));
 
27447
#endif
 
27448
        DUK_FFLUSH(DUK_STDERR);
 
27449
 
 
27450
        va_end(ap);
 
27451
}
 
27452
 
 
27453
#endif  /* DUK_USE_VARIADIC_MACROS */
 
27454
 
 
27455
#else  /* DUK_USE_DEBUG */
 
27456
 
 
27457
/*
 
27458
 *  Debugging disabled
 
27459
 */
 
27460
 
 
27461
#endif  /* DUK_USE_DEBUG */
 
27462
 
 
27463
#line 1 "duk_debug_vsnprintf.c"
 
27464
/*
 
27465
 *  Custom formatter for debug printing, allowing Duktape specific data
 
27466
 *  structures (such as tagged values and heap objects) to be printed with
 
27467
 *  a nice format string.  Because debug printing should not affect execution
 
27468
 *  state, formatting here must be independent of execution (see implications
 
27469
 *  below) and must not allocate memory.
 
27470
 *
 
27471
 *  Custom format tags begin with a '%!' to safely distinguish them from
 
27472
 *  standard format tags.  The following conversions are supported:
 
27473
 *
 
27474
 *     %!T    tagged value (duk_tval *)
 
27475
 *     %!O    heap object (duk_heaphdr *)
 
27476
 *     %!I    decoded bytecode instruction
 
27477
 *     %!C    bytecode instruction opcode name
 
27478
 *
 
27479
 *  Everything is serialized in a JSON-like manner.  The default depth is one
 
27480
 *  level, internal prototype is not followed, and internal properties are not
 
27481
 *  serialized.  The following modifiers change this behavior:
 
27482
 *
 
27483
 *     @      print pointers
 
27484
 *     #      print binary representations (where applicable)
 
27485
 *     d      deep traversal of own properties (not prototype)
 
27486
 *     p      follow prototype chain (useless without 'd')
 
27487
 *     i      include internal properties (other than prototype)
 
27488
 *     x      hexdump buffers
 
27489
 *     h      heavy formatting
 
27490
 *
 
27491
 *  For instance, the following serializes objects recursively, but does not
 
27492
 *  follow the prototype chain nor print internal properties: "%!dO".
 
27493
 *
 
27494
 *  Notes:
 
27495
 *
 
27496
 *    * Standard snprintf return value semantics seem to vary.  This
 
27497
 *      implementation returns the number of bytes it actually wrote
 
27498
 *      (excluding the null terminator).  If retval == buffer size,
 
27499
 *      output was truncated (except for corner cases).
 
27500
 *
 
27501
 *    * Output format is intentionally different from Ecmascript
 
27502
 *      formatting requirements, as formatting here serves debugging
 
27503
 *      of internals.
 
27504
 *
 
27505
 *    * Depth checking (and updating) is done in each type printer
 
27506
 *      separately, to allow them to call each other freely.
 
27507
 *
 
27508
 *    * Some pathological structures might take ages to print (e.g.
 
27509
 *      self recursion with 100 properties pointing to the object
 
27510
 *      itself).  To guard against these, each printer also checks
 
27511
 *      whether the output buffer is full; if so, early exit.
 
27512
 *
 
27513
 *    * Reference loops are detected using a loop stack.
 
27514
 */
 
27515
 
 
27516
/* include removed: duk_internal.h */
 
27517
 
 
27518
#ifdef DUK_USE_DEBUG
 
27519
 
 
27520
#include <stdio.h>
 
27521
#include <stdarg.h>
 
27522
#include <string.h>
 
27523
 
 
27524
/* list of conversion specifiers that terminate a format tag;
 
27525
 * this is unfortunately guesswork.
 
27526
 */
 
27527
#define DUK__ALLOWED_STANDARD_SPECIFIERS  "diouxXeEfFgGaAcsCSpnm"
 
27528
 
 
27529
/* maximum length of standard format tag that we support */
 
27530
#define DUK__MAX_FORMAT_TAG_LENGTH  32
 
27531
 
 
27532
/* heapobj recursion depth when deep printing is selected */
 
27533
#define DUK__DEEP_DEPTH_LIMIT  8
 
27534
 
 
27535
/* maximum recursion depth for loop detection stacks */
 
27536
#define DUK__LOOP_STACK_DEPTH  256
 
27537
 
 
27538
/* must match bytecode defines now; build autogenerate? */
 
27539
static const char *duk__bc_optab[] = {
 
27540
        "LDREG",    "STREG",    "LDCONST",  "LDINT",    "LDINTX",   "MPUTOBJ",  "MPUTOBJI", "MPUTARR",  "MPUTARRI", "NEW",
 
27541
        "NEWI",     "REGEXP",   "CSREG",    "CSREGI",   "GETVAR",   "PUTVAR",   "DECLVAR",  "DELVAR",   "CSVAR",    "CSVARI",
 
27542
        "CLOSURE",  "GETPROP",  "PUTPROP",  "DELPROP",  "CSPROP",   "CSPROPI",  "ADD",      "SUB",      "MUL",      "DIV",
 
27543
        "MOD",      "BAND",     "BOR",      "BXOR",     "BASL",     "BLSR",     "BASR",     "BNOT",     "LNOT",     "EQ",
 
27544
        "NEQ",      "SEQ",      "SNEQ",     "GT",       "GE",       "LT",       "LE",       "IF",       "INSTOF",   "IN",
 
27545
        "JUMP",     "RETURN",   "CALL",     "CALLI",    "LABEL",    "ENDLABEL", "BREAK",    "CONTINUE", "TRYCATCH", "UNUSED59",
 
27546
        "UNUSED60", "EXTRA",    "DEBUG",    "INVALID",
 
27547
};
 
27548
 
 
27549
static const char *duk__bc_extraoptab[] = {
 
27550
        "NOP", "LDTHIS", "LDUNDEF", "LDNULL", "LDTRUE", "LDFALSE", "NEWOBJ", "NEWARR", "SETALEN", "TYPEOF",
 
27551
        "TYPEOFID", "TONUM", "INITENUM", "NEXTENUM", "INITSET", "INITSETI", "INITGET", "INITGETI", "ENDTRY", "ENDCATCH",
 
27552
        "ENDFIN", "THROW", "INVLHS", "UNM", "UNP", "INC", "DEC", "XXX", "XXX", "XXX",
 
27553
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27554
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27555
 
 
27556
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27557
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27558
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27559
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27560
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27561
 
 
27562
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27563
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27564
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27565
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27566
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27567
 
 
27568
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27569
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27570
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27571
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27572
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27573
 
 
27574
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27575
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27576
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27577
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27578
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27579
 
 
27580
        "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
 
27581
};
 
27582
 
 
27583
typedef struct duk__dprint_state duk__dprint_state;
 
27584
struct duk__dprint_state {
 
27585
        duk_fixedbuffer *fb;
 
27586
 
 
27587
        /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
 
27588
         * to not couple these two mechanisms unnecessarily.
 
27589
         */
 
27590
        duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
 
27591
        int loop_stack_index;
 
27592
        int loop_stack_limit;
 
27593
 
 
27594
        int depth;
 
27595
        int depth_limit;
 
27596
 
 
27597
        int pointer;
 
27598
        int heavy;
 
27599
        int binary;
 
27600
        int follow_proto;
 
27601
        int internal;
 
27602
        int hexdump;
 
27603
};
 
27604
 
 
27605
/* helpers */
 
27606
static void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, int quotes);
 
27607
static void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
 
27608
static void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
 
27609
static void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
 
27610
static void duk__print_instr(duk__dprint_state *st, duk_instr ins);
 
27611
static void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
 
27612
static void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
 
27613
static void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
 
27614
 
 
27615
static void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
 
27616
        duk_fixedbuffer *fb = st->fb;
 
27617
 
 
27618
        if (st->heavy) {
 
27619
                duk_fb_sprintf(fb, "(%p)", (void *) h);
 
27620
        }
 
27621
 
 
27622
        if (!h) {
 
27623
                return;
 
27624
        }
 
27625
 
 
27626
        if (st->binary) {
 
27627
                duk_size_t i;
 
27628
                duk_fb_put_byte(fb, (duk_uint8_t) '[');
 
27629
                for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
 
27630
                        duk_fb_sprintf(fb, "%02x", (int) ((unsigned char *)h)[i]);
 
27631
                }
 
27632
                duk_fb_put_byte(fb, (duk_uint8_t) ']');
 
27633
        }
 
27634
 
 
27635
#ifdef DUK_USE_REFERENCE_COUNTING  /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
 
27636
        if (st->heavy) {
 
27637
                duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%u,h_flags=%08x,type=%d,reachable=%d,temproot=%d,finalizable=%d,finalized=%d]",
 
27638
                               DUK_HEAPHDR_GET_NEXT(h),
 
27639
                               DUK_HEAPHDR_GET_PREV(h),
 
27640
                               DUK_HEAPHDR_GET_REFCOUNT(h),
 
27641
                               DUK_HEAPHDR_GET_FLAGS(h),
 
27642
                               DUK_HEAPHDR_GET_TYPE(h),
 
27643
                               DUK_HEAPHDR_HAS_REACHABLE(h),
 
27644
                               DUK_HEAPHDR_HAS_TEMPROOT(h),
 
27645
                               DUK_HEAPHDR_HAS_FINALIZABLE(h),
 
27646
                               DUK_HEAPHDR_HAS_FINALIZED(h));
 
27647
        }
 
27648
#else
 
27649
        if (st->heavy) {
 
27650
                duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08x,type=%d,reachable=%d,temproot=%d,finalizable=%d,finalized=%d]",
 
27651
                               DUK_HEAPHDR_GET_NEXT(h),
 
27652
                               DUK_HEAPHDR_GET_FLAGS(h),
 
27653
                               DUK_HEAPHDR_GET_TYPE(h),
 
27654
                               DUK_HEAPHDR_HAS_REACHABLE(h),
 
27655
                               DUK_HEAPHDR_HAS_TEMPROOT(h),
 
27656
                               DUK_HEAPHDR_HAS_FINALIZABLE(h),
 
27657
                               DUK_HEAPHDR_HAS_FINALIZED(h));
 
27658
        }
 
27659
#endif
 
27660
}
 
27661
 
 
27662
static void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
 
27663
        duk_fixedbuffer *fb = st->fb;
 
27664
 
 
27665
        if (st->heavy) {
 
27666
                duk_fb_sprintf(fb, "(%p)", (void *) h);
 
27667
        }
 
27668
 
 
27669
        if (!h) {
 
27670
                return;
 
27671
        }
 
27672
 
 
27673
        if (st->binary) {
 
27674
                duk_size_t i;
 
27675
                duk_fb_put_byte(fb, (duk_uint8_t) '[');
 
27676
                for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
 
27677
                        duk_fb_sprintf(fb, "%02x", (int) ((unsigned char *)h)[i]);
 
27678
                }
 
27679
                duk_fb_put_byte(fb, (duk_uint8_t) ']');
 
27680
        }
 
27681
 
 
27682
#ifdef DUK_USE_REFERENCE_COUNTING
 
27683
        if (st->heavy) {
 
27684
                duk_fb_sprintf(fb, "[h_refcount=%u,h_flags=%08x,type=%d,reachable=%d,temproot=%d,finalizable=%d,finalized=%d]",
 
27685
                               DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
 
27686
                               DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
 
27687
                               DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
 
27688
                               DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h),
 
27689
                               DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h),
 
27690
                               DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h),
 
27691
                               DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h));
 
27692
        }
 
27693
#else
 
27694
        if (st->heavy) {
 
27695
                duk_fb_sprintf(fb, "[h_flags=%08x,type=%d,reachable=%d,temproot=%d,finalizable=%d,finalized=%d]",
 
27696
                               DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
 
27697
                               DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
 
27698
                               DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h),
 
27699
                               DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h),
 
27700
                               DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h),
 
27701
                               DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h));
 
27702
        }
 
27703
#endif
 
27704
}
 
27705
 
 
27706
static void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, int quotes) {
 
27707
        duk_fixedbuffer *fb = st->fb;
 
27708
        duk_uint8_t *p;
 
27709
        duk_uint8_t *p_end;
 
27710
 
 
27711
        /* terminal type: no depth check */
 
27712
 
 
27713
        if (duk_fb_is_full(fb)) {
 
27714
                return;
 
27715
        }
 
27716
 
 
27717
        duk__print_shared_heaphdr_string(st, &h->hdr);
 
27718
 
 
27719
        if (!h) {
 
27720
                duk_fb_put_cstring(fb, "NULL");
 
27721
                return;
 
27722
        }
 
27723
 
 
27724
        p = DUK_HSTRING_GET_DATA(h);
 
27725
        p_end = p + DUK_HSTRING_GET_BYTELEN(h);
 
27726
 
 
27727
        if (p_end > p && p[0] == '_') {
 
27728
                /* if property key begins with underscore, encode it with
 
27729
                 * forced quotes (e.g. "_foo") to distinguish it from encoded
 
27730
                 * internal properties (e.g. \xffbar -> _bar).
 
27731
                 */
 
27732
                quotes = 1;
 
27733
        }
 
27734
 
 
27735
        if (quotes) {
 
27736
                duk_fb_put_byte(fb, (duk_uint8_t) '"');
 
27737
        }
 
27738
        while (p < p_end) {
 
27739
                duk_uint8_t ch = *p++;
 
27740
 
 
27741
                /* two special escapes: '\' and '"', other printables as is */
 
27742
                if (ch == '\\') {
 
27743
                        duk_fb_sprintf(fb, "\\\\");
 
27744
                } else if (ch == '"') {
 
27745
                        duk_fb_sprintf(fb, "\\\"");
 
27746
                } else if (ch >= 0x20 && ch <= 0x7e) {
 
27747
                        duk_fb_put_byte(fb, ch);
 
27748
                } else if (ch == 0xff && !quotes) {
 
27749
                        /* encode \xffbar as _bar if no quotes are applied, this is for
 
27750
                         * readable internal keys.
 
27751
                         */
 
27752
                        duk_fb_put_byte(fb, (duk_uint8_t) '_');
 
27753
                } else {
 
27754
                        duk_fb_sprintf(fb, "\\x%02x", (int) ch);
 
27755
                }
 
27756
        }
 
27757
        if (quotes) {
 
27758
                duk_fb_put_byte(fb, (duk_uint8_t) '"');
 
27759
        }
 
27760
#ifdef DUK_USE_REFERENCE_COUNTING
 
27761
        /* XXX: limit to quoted strings only, to save keys from being cluttered? */
 
27762
        duk_fb_sprintf(fb, "/%d", DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
 
27763
#endif
 
27764
}
 
27765
 
 
27766
#ifdef DUK__COMMA
 
27767
#undef DUK__COMMA
 
27768
#endif
 
27769
#define DUK__COMMA()  do { \
 
27770
                if (first) { \
 
27771
                        first = 0; \
 
27772
                } else { \
 
27773
                        duk_fb_put_byte(fb, (duk_uint8_t) ','); \
 
27774
                } \
 
27775
        } while (0)
 
27776
 
 
27777
static void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
 
27778
        duk_fixedbuffer *fb = st->fb;
 
27779
        duk_uint_fast32_t i;
 
27780
        duk_tval *tv;
 
27781
        duk_hstring *key;
 
27782
        int first = 1;
 
27783
        char *brace1 = "{";
 
27784
        char *brace2 = "}";
 
27785
        int pushed_loopstack = 0;
 
27786
 
 
27787
        if (duk_fb_is_full(fb)) {
 
27788
                return;
 
27789
        }
 
27790
 
 
27791
        duk__print_shared_heaphdr(st, &h->hdr);
 
27792
 
 
27793
        if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
 
27794
                brace1 = "[";
 
27795
                brace2 = "]";
 
27796
        }
 
27797
 
 
27798
        if (!h) {
 
27799
                duk_fb_put_cstring(fb, "NULL");
 
27800
                goto finished;
 
27801
        }
 
27802
 
 
27803
        if (st->depth >= st->depth_limit) {
 
27804
                if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
27805
                        duk_fb_sprintf(fb, "%sobject/compiledfunction %p%s", brace1, (void *) h, brace2);
 
27806
                } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
27807
                        duk_fb_sprintf(fb, "%sobject/nativefunction %p%s", brace1, (void *) h, brace2);
 
27808
                } else if (DUK_HOBJECT_IS_THREAD(h)) {
 
27809
                        duk_fb_sprintf(fb, "%sobject/thread %p%s", brace1, (void *) h, brace2);
 
27810
                } else {
 
27811
                        duk_fb_sprintf(fb, "%sobject %p%s", brace1, (void *) h, brace2);  /* may be NULL */
 
27812
                }
 
27813
                return;
 
27814
        }
 
27815
 
 
27816
        for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
 
27817
                if (st->loop_stack[i] == h) {
 
27818
                        duk_fb_sprintf(fb, "%sLOOP:%p%s", brace1, (void *) h, brace2);
 
27819
                        return;
 
27820
                }
 
27821
        }
 
27822
 
 
27823
        /* after this, return paths should 'goto finished' for decrement */
 
27824
        st->depth++;
 
27825
 
 
27826
        if (st->loop_stack_index >= st->loop_stack_limit) {
 
27827
                duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", brace1, brace2);
 
27828
                goto finished;
 
27829
        }
 
27830
        st->loop_stack[st->loop_stack_index++] = h;
 
27831
        pushed_loopstack = 1;
 
27832
 
 
27833
        /*
 
27834
         *  Notation: double underscore used for internal properties which are not
 
27835
         *  stored in the property allocation (e.g. '__valstack').
 
27836
         */
 
27837
 
 
27838
        duk_fb_put_cstring(fb, brace1);
 
27839
 
 
27840
        if (h->p) {
 
27841
                duk_uint32_t a_limit;
 
27842
 
 
27843
                a_limit = h->a_size;
 
27844
                if (st->internal) {
 
27845
                        /* dump all allocated entries, unused entries print as 'unused',
 
27846
                         * note that these may extend beyond current 'length' and look
 
27847
                         * a bit funny.
 
27848
                         */
 
27849
                } else {
 
27850
                        /* leave out trailing 'unused' elements */
 
27851
                        while (a_limit > 0) {
 
27852
                                tv = DUK_HOBJECT_A_GET_VALUE_PTR(h, a_limit - 1);
 
27853
                                if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
27854
                                        break;
 
27855
                                }
 
27856
                                a_limit--;
 
27857
                        }
 
27858
                }
 
27859
 
 
27860
                for (i = 0; i < a_limit; i++) {
 
27861
                        tv = DUK_HOBJECT_A_GET_VALUE_PTR(h, i);
 
27862
                        DUK__COMMA();
 
27863
                        duk__print_tval(st, tv);
 
27864
                }
 
27865
                for (i = 0; i < h->e_used; i++) {
 
27866
                        key = DUK_HOBJECT_E_GET_KEY(h, i);
 
27867
                        if (!key) {
 
27868
                                continue;
 
27869
                        }
 
27870
                        if (!st->internal &&
 
27871
                            DUK_HSTRING_GET_BYTELEN(key) > 0 &&
 
27872
                            DUK_HSTRING_GET_DATA(key)[0] == 0xff) {
 
27873
                                /* FIXME: cleanup to use DUK_HSTRING_FLAG_INTERNAL? */
 
27874
                                continue;
 
27875
                        }
 
27876
                        DUK__COMMA();
 
27877
                        duk__print_hstring(st, key, 0);
 
27878
                        duk_fb_put_byte(fb, (duk_uint8_t) ':');
 
27879
                        if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h, i)) {
 
27880
                                duk_fb_sprintf(fb, "[get:%p,set:%p]",
 
27881
                                               DUK_HOBJECT_E_GET_VALUE(h, i).a.get,
 
27882
                                               DUK_HOBJECT_E_GET_VALUE(h, i).a.set);
 
27883
                        } else {
 
27884
                                tv = &DUK_HOBJECT_E_GET_VALUE(h, i).v;
 
27885
                                duk__print_tval(st, tv);
 
27886
                        }
 
27887
                        if (st->heavy) {
 
27888
                                duk_fb_sprintf(fb, "<%02x>", (int) DUK_HOBJECT_E_GET_FLAGS(h, i));
 
27889
                        }
 
27890
                }
 
27891
        }
 
27892
        if (st->internal) {
 
27893
                if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
 
27894
                        DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
 
27895
                } else {
 
27896
                        ;
 
27897
                }
 
27898
                if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
 
27899
                        DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
 
27900
                } else {
 
27901
                        ;
 
27902
                }
 
27903
                if (DUK_HOBJECT_HAS_BOUND(h)) {
 
27904
                        DUK__COMMA(); duk_fb_sprintf(fb, "__bound:true");
 
27905
                } else {
 
27906
                        ;
 
27907
                }
 
27908
                if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)) {
 
27909
                        DUK__COMMA(); duk_fb_sprintf(fb, "__compiledfunction:true");
 
27910
                } else {
 
27911
                        ;
 
27912
                }
 
27913
                if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
 
27914
                        DUK__COMMA(); duk_fb_sprintf(fb, "__nativefunction:true");
 
27915
                } else {
 
27916
                        ;
 
27917
                }
 
27918
                if (DUK_HOBJECT_HAS_THREAD(h)) {
 
27919
                        DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
 
27920
                } else {
 
27921
                        ;
 
27922
                }
 
27923
                if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
 
27924
                        DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
 
27925
                } else {
 
27926
                        ;
 
27927
                }
 
27928
                if (DUK_HOBJECT_HAS_STRICT(h)) {
 
27929
                        DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
 
27930
                } else {
 
27931
                        ;
 
27932
                }
 
27933
                if (DUK_HOBJECT_HAS_NEWENV(h)) {
 
27934
                        DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
 
27935
                } else {
 
27936
                        ;
 
27937
                }
 
27938
                if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
 
27939
                        DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
 
27940
                } else {
 
27941
                        ;
 
27942
                }
 
27943
                if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
 
27944
                        DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
 
27945
                } else {
 
27946
                        ;
 
27947
                }
 
27948
                if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
 
27949
                        DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
 
27950
                } else {
 
27951
                        ;
 
27952
                }
 
27953
                if (DUK_HOBJECT_HAS_SPECIAL_ARRAY(h)) {
 
27954
                        DUK__COMMA(); duk_fb_sprintf(fb, "__special_array:true");
 
27955
                } else {
 
27956
                        ;
 
27957
                }
 
27958
                if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(h)) {
 
27959
                        DUK__COMMA(); duk_fb_sprintf(fb, "__special_stringobj:true");
 
27960
                } else {
 
27961
                        ;
 
27962
                }
 
27963
                if (DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(h)) {
 
27964
                        DUK__COMMA(); duk_fb_sprintf(fb, "__special_arguments:true");
 
27965
                } else {
 
27966
                        ;
 
27967
                }
 
27968
        }
 
27969
        if (st->internal && DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
27970
                duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
 
27971
                DUK__COMMA(); duk_fb_put_cstring(fb, "__data:"); duk__print_hbuffer(st, f->data);
 
27972
                DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%d", f->nregs);
 
27973
                DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%d", f->nargs);
 
27974
        } else if (st->internal && DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
27975
                duk_hnativefunction *f = (duk_hnativefunction *) h;
 
27976
#if 0  /* FIXME: no portable way to print function pointers */
 
27977
                DUK__COMMA(); duk_fb_sprintf(fb, "__func:%p", (void *) f->func);
 
27978
#endif
 
27979
                DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%d", f->nargs);
 
27980
 
 
27981
        } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
 
27982
                duk_hthread *t = (duk_hthread *) h;
 
27983
                DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%d", t->strict);
 
27984
                DUK__COMMA(); duk_fb_sprintf(fb, "__state:%d", t->state);
 
27985
                DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%d", t->unused1);
 
27986
                DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%d", t->unused2);
 
27987
                DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%d", t->valstack_max);
 
27988
                DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%d", t->callstack_max);
 
27989
                DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%d", t->catchstack_max);
 
27990
                DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
 
27991
                DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%d", (void *) t->valstack_end, (int) (t->valstack_end - t->valstack));
 
27992
                DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%d", (void *) t->valstack_bottom, (int) (t->valstack_bottom - t->valstack));
 
27993
                DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%d", (void *) t->valstack_top, (int) (t->valstack_top - t->valstack));
 
27994
                DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
 
27995
                DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%d", t->catchstack_size);
 
27996
                DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%d", t->catchstack_top);
 
27997
                DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
 
27998
                /* XXX: print built-ins array? */
 
27999
 
 
28000
        }
 
28001
#ifdef DUK_USE_REFERENCE_COUNTING
 
28002
        if (st->internal) {
 
28003
                DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%d", DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
 
28004
        }
 
28005
#endif
 
28006
        if (st->internal) {
 
28007
                DUK__COMMA(); duk_fb_sprintf(fb, "__class:%d", DUK_HOBJECT_GET_CLASS_NUMBER(h));
 
28008
        }
 
28009
 
 
28010
        /* prototype should be last, for readability */
 
28011
        if (st->follow_proto && h->prototype) {
 
28012
                DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, h->prototype);
 
28013
        }
 
28014
 
 
28015
        duk_fb_put_cstring(fb, brace2);
 
28016
 
 
28017
        if (st->heavy && h->h_size > 0) {
 
28018
                duk_fb_put_byte(fb, (duk_uint8_t) '<');
 
28019
                for (i = 0; i < h->h_size; i++) {
 
28020
                        duk_uint32_t h_idx = DUK_HOBJECT_H_GET_INDEX(h, i);
 
28021
                        if (i > 0) {
 
28022
                                duk_fb_put_byte(fb, (duk_uint8_t) ',');
 
28023
                        }
 
28024
                        if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
 
28025
                                duk_fb_sprintf(fb, "u");
 
28026
                        } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
 
28027
                                duk_fb_sprintf(fb, "d");
 
28028
                        } else {
 
28029
                                duk_fb_sprintf(fb, "%d", (int) h_idx);
 
28030
                        }
 
28031
                }
 
28032
                duk_fb_put_byte(fb, (duk_uint8_t) '>');
 
28033
        }
 
28034
 
 
28035
 finished:
 
28036
        st->depth--;
 
28037
        if (pushed_loopstack) {
 
28038
                st->loop_stack_index--;
 
28039
                st->loop_stack[st->loop_stack_index] = NULL;
 
28040
        }
 
28041
}
 
28042
 
 
28043
#undef DUK__COMMA
 
28044
 
 
28045
static void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
 
28046
        duk_fixedbuffer *fb = st->fb;
 
28047
        size_t i, n;
 
28048
        duk_uint8_t *p;
 
28049
 
 
28050
        if (duk_fb_is_full(fb)) {
 
28051
                return;
 
28052
        }
 
28053
 
 
28054
        /* terminal type: no depth check */
 
28055
 
 
28056
        if (!h) {
 
28057
                duk_fb_put_cstring(fb, "NULL");
 
28058
                return;
 
28059
        }
 
28060
 
 
28061
        if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
 
28062
                duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
 
28063
                duk_fb_sprintf(fb, "buffer:dynamic:%p:%d:%d",
 
28064
                               g->curr_alloc, g->size, g->usable_size);
 
28065
        } else {
 
28066
                duk_fb_sprintf(fb, "buffer:fixed:%d", DUK_HBUFFER_GET_SIZE(h));
 
28067
        }
 
28068
 
 
28069
#ifdef DUK_USE_REFERENCE_COUNTING
 
28070
        duk_fb_sprintf(fb, "/%d", DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
 
28071
#endif
 
28072
 
 
28073
        if (st->hexdump) {
 
28074
                duk_fb_sprintf(fb, "=[");
 
28075
                n = DUK_HBUFFER_GET_SIZE(h);
 
28076
                p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
 
28077
                for (i = 0; i < n; i++) {
 
28078
                        duk_fb_sprintf(fb, "%02x", (int) p[i]);
 
28079
                }
 
28080
                duk_fb_sprintf(fb, "]");
 
28081
        }
 
28082
}
 
28083
 
 
28084
static void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
 
28085
        duk_fixedbuffer *fb = st->fb;
 
28086
 
 
28087
        if (duk_fb_is_full(fb)) {
 
28088
                return;
 
28089
        }
 
28090
 
 
28091
        if (!h) {
 
28092
                duk_fb_put_cstring(fb, "NULL");
 
28093
                return;
 
28094
        }
 
28095
 
 
28096
        switch (DUK_HEAPHDR_GET_TYPE(h)) {
 
28097
        case DUK_HTYPE_STRING:
 
28098
                duk__print_hstring(st, (duk_hstring *) h, 1);
 
28099
                break;
 
28100
        case DUK_HTYPE_OBJECT:
 
28101
                duk__print_hobject(st, (duk_hobject *) h);
 
28102
                break;
 
28103
        case DUK_HTYPE_BUFFER:
 
28104
                duk__print_hbuffer(st, (duk_hbuffer *) h);
 
28105
                break;
 
28106
        default:
 
28107
                duk_fb_sprintf(fb, "[unknown htype %d]", DUK_HEAPHDR_GET_TYPE(h));
 
28108
                break;
 
28109
        }
 
28110
}
 
28111
 
 
28112
static void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
 
28113
        duk_fixedbuffer *fb = st->fb;
 
28114
 
 
28115
        if (duk_fb_is_full(fb)) {
 
28116
                return;
 
28117
        }
 
28118
 
 
28119
        /* depth check is done when printing an actual type */
 
28120
 
 
28121
        if (st->heavy) {
 
28122
                duk_fb_sprintf(fb, "(%p)", (void *) tv);
 
28123
        }
 
28124
 
 
28125
        if (!tv) {
 
28126
                duk_fb_put_cstring(fb, "NULL");
 
28127
                return;
 
28128
        }
 
28129
 
 
28130
        if (st->binary) {
 
28131
                duk_size_t i;
 
28132
                duk_fb_put_byte(fb, (duk_uint8_t) '[');
 
28133
                for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
 
28134
                        duk_fb_sprintf(fb, "%02x", (int) ((unsigned char *)tv)[i]);
 
28135
                }
 
28136
                duk_fb_put_byte(fb, (duk_uint8_t) ']');
 
28137
        }
 
28138
 
 
28139
        if (st->heavy) {
 
28140
                duk_fb_put_byte(fb, (duk_uint8_t) '<');
 
28141
        }
 
28142
        switch (DUK_TVAL_GET_TAG(tv)) {
 
28143
        case DUK_TAG_UNDEFINED: {
 
28144
                if (DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
28145
                        duk_fb_put_cstring(fb, "unused");
 
28146
                } else {
 
28147
                        duk_fb_put_cstring(fb, "undefined");
 
28148
                }
 
28149
                break;
 
28150
        }
 
28151
        case DUK_TAG_NULL: {
 
28152
                duk_fb_put_cstring(fb, "null");
 
28153
                break;
 
28154
        }
 
28155
        case DUK_TAG_BOOLEAN: {
 
28156
                duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
 
28157
                break;
 
28158
        }
 
28159
        case DUK_TAG_STRING: {
 
28160
                /* Note: string is a terminal heap object, so no depth check here */
 
28161
                duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
 
28162
                break;
 
28163
        }
 
28164
        case DUK_TAG_OBJECT: {
 
28165
                duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
 
28166
                break;
 
28167
        }
 
28168
        case DUK_TAG_BUFFER: {
 
28169
                duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
 
28170
                break;
 
28171
        }
 
28172
        case DUK_TAG_POINTER: {
 
28173
                duk_fb_sprintf(fb, "pointer:%p", DUK_TVAL_GET_POINTER(tv));
 
28174
                break;
 
28175
        }
 
28176
        default: {
 
28177
                /* IEEE double is approximately 16 decimal digits; print a couple extra */
 
28178
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
28179
                duk_fb_sprintf(fb, "%.18g", DUK_TVAL_GET_NUMBER(tv));
 
28180
                break;
 
28181
        }
 
28182
        }
 
28183
        if (st->heavy) {
 
28184
                duk_fb_put_byte(fb, (duk_uint8_t) '>');
 
28185
        }
 
28186
}
 
28187
 
 
28188
static void duk__print_instr(duk__dprint_state *st, duk_instr ins) {
 
28189
        duk_fixedbuffer *fb = st->fb;
 
28190
        int op;
 
28191
        const char *op_name;
 
28192
        const char *extraop_name;
 
28193
 
 
28194
        op = DUK_DEC_OP(ins);
 
28195
        op_name = duk__bc_optab[op];
 
28196
 
 
28197
        /* FIXME: option to fix opcode length so it lines up nicely */
 
28198
 
 
28199
        if (op == DUK_OP_EXTRA) {
 
28200
                extraop_name = duk__bc_extraoptab[DUK_DEC_A(ins)];
 
28201
 
 
28202
                duk_fb_sprintf(fb, "%s %d, %d",
 
28203
                               extraop_name, DUK_DEC_B(ins), DUK_DEC_C(ins));
 
28204
        } else if (op == DUK_OP_JUMP) {
 
28205
                int diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;  /* from next pc */
 
28206
                int diff2 = diff1 + 1;                            /* from curr pc */
 
28207
 
 
28208
                duk_fb_sprintf(fb, "%s %d (to pc%c%d)",
 
28209
                               op_name, diff1, (diff2 >= 0 ? '+' : '-'), (diff2 >= 0 ? diff2 : -diff2));
 
28210
        } else {
 
28211
                duk_fb_sprintf(fb, "%s %d, %d, %d",
 
28212
                               op_name, DUK_DEC_A(ins), DUK_DEC_B(ins), DUK_DEC_C(ins));
 
28213
        }
 
28214
}
 
28215
 
 
28216
static void duk__print_opcode(duk__dprint_state *st, int opcode) {
 
28217
        duk_fixedbuffer *fb = st->fb;
 
28218
 
 
28219
        if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
 
28220
                duk_fb_sprintf(fb, "?(%d)", opcode);
 
28221
        } else {
 
28222
                duk_fb_sprintf(fb, "%s", duk__bc_optab[opcode]);
 
28223
        }
 
28224
}
 
28225
 
 
28226
int duk_debug_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
 
28227
        duk_fixedbuffer fb;
 
28228
        const char *p = format;
 
28229
        const char *p_end = p + DUK_STRLEN(format);
 
28230
        int retval;
 
28231
        
 
28232
        DUK_MEMZERO(&fb, sizeof(fb));
 
28233
        fb.buffer = (duk_uint8_t *) str;
 
28234
        fb.length = size;
 
28235
        fb.offset = 0;
 
28236
        fb.truncated = 0;
 
28237
 
 
28238
        while (p < p_end) {
 
28239
                char ch = *p++;
 
28240
                const char *p_begfmt = NULL;
 
28241
                int got_exclamation = 0;
 
28242
                duk__dprint_state st;
 
28243
 
 
28244
                if (ch != '%') {
 
28245
                        duk_fb_put_byte(&fb, (duk_uint8_t) ch);
 
28246
                        continue;
 
28247
                }
 
28248
 
 
28249
                /*
 
28250
                 *  Format tag parsing.  Since we don't understand all the
 
28251
                 *  possible format tags allowed, we just scan for a terminating
 
28252
                 *  specifier and keep track of relevant modifiers that we do
 
28253
                 *  understand.  See man 3 printf.
 
28254
                 */
 
28255
 
 
28256
                DUK_MEMZERO(&st, sizeof(st));
 
28257
                st.fb = &fb;
 
28258
                st.depth = 0;
 
28259
                st.depth_limit = 1;
 
28260
                st.loop_stack_index = 0;
 
28261
                st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
 
28262
 
 
28263
                p_begfmt = p - 1;
 
28264
                while (p < p_end) {
 
28265
                        ch = *p++;
 
28266
 
 
28267
                        if (ch == '*') {
 
28268
                                /* unsupported: would consume multiple args */
 
28269
                                goto error;
 
28270
                        } else if (ch == '%') {
 
28271
                                duk_fb_put_byte(&fb, (duk_uint8_t) '%');
 
28272
                                break;
 
28273
                        } else if (ch == '!') {
 
28274
                                got_exclamation = 1;
 
28275
                        } else if (got_exclamation && ch == 'd') {
 
28276
                                st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
 
28277
                        } else if (got_exclamation && ch == 'p') {
 
28278
                                st.follow_proto = 1;
 
28279
                        } else if (got_exclamation && ch == 'i') {
 
28280
                                st.internal = 1;
 
28281
                        } else if (got_exclamation && ch == 'x') {
 
28282
                                st.hexdump = 1;
 
28283
                        } else if (got_exclamation && ch == 'h') {
 
28284
                                st.heavy = 1;
 
28285
                        } else if (got_exclamation && ch == '@') {
 
28286
                                st.pointer = 1;
 
28287
                        } else if (got_exclamation && ch == '#') {
 
28288
                                st.binary = 1;
 
28289
                        } else if (got_exclamation && ch == 'T') {
 
28290
                                duk_tval *t = va_arg(ap, duk_tval *);
 
28291
                                if (st.pointer && !st.heavy) {
 
28292
                                        duk_fb_sprintf(&fb, "(%p)", (void *) t);
 
28293
                                }
 
28294
                                duk__print_tval(&st, t);
 
28295
                                break;
 
28296
                        } else if (got_exclamation && ch == 'O') {
 
28297
                                duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
 
28298
                                if (st.pointer && !st.heavy) {
 
28299
                                        duk_fb_sprintf(&fb, "(%p)", (void *) t);
 
28300
                                }
 
28301
                                duk__print_heaphdr(&st, t);
 
28302
                                break;
 
28303
                        } else if (got_exclamation && ch == 'I') {
 
28304
                                duk_instr t = va_arg(ap, duk_instr);
 
28305
                                duk__print_instr(&st, t);
 
28306
                                break;
 
28307
                        } else if (got_exclamation && ch == 'C') {
 
28308
                                int t = va_arg(ap, int);
 
28309
                                duk__print_opcode(&st, t);
 
28310
                                break;
 
28311
                        } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
 
28312
                                char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
 
28313
                                duk_size_t fmtlen;
 
28314
 
 
28315
                                DUK_ASSERT(p >= p_begfmt);
 
28316
                                fmtlen = (duk_size_t) (p - p_begfmt);
 
28317
                                if (fmtlen >= sizeof(fmtbuf)) {
 
28318
                                        /* format is too large, abort */
 
28319
                                        goto error;
 
28320
                                }
 
28321
                                DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
 
28322
                                DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
 
28323
 
 
28324
                                /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
 
28325
                                 * depends on type though.
 
28326
                                 */
 
28327
 
 
28328
                                /* FIXME: check size for other types.. actually it would be best to switch
 
28329
                                 * for supported standard formats and get args explicitly
 
28330
                                 */
 
28331
                                if (ch == 'f' || ch == 'g' || ch == 'e') {
 
28332
                                        double arg;
 
28333
                                        arg = va_arg(ap, double);
 
28334
                                        duk_fb_sprintf(&fb, fmtbuf, arg);
 
28335
                                } else {
 
28336
                                        void *arg;
 
28337
                                        arg = va_arg(ap, void *);
 
28338
                                        duk_fb_sprintf(&fb, fmtbuf, arg);
 
28339
                                }
 
28340
                                break;
 
28341
                        } else {
 
28342
                                /* ignore */
 
28343
                        }
 
28344
                }
 
28345
        }
 
28346
        goto done;
 
28347
 
 
28348
 error:
 
28349
        duk_fb_put_cstring(&fb, "FMTERR");
 
28350
        /* fall through */
 
28351
 
 
28352
 done:
 
28353
        retval = fb.offset;
 
28354
        duk_fb_put_byte(&fb, (duk_uint8_t) 0);
 
28355
 
 
28356
        /* return total chars written excluding terminator */
 
28357
        return retval;
 
28358
}
 
28359
 
 
28360
int duk_debug_snprintf(char *str, size_t size, const char *format, ...) {
 
28361
        int retval;
 
28362
        va_list ap;
 
28363
        va_start(ap, format);
 
28364
        retval = duk_debug_vsnprintf(str, size, format, ap);
 
28365
        va_end(ap);
 
28366
        return retval;
 
28367
}
 
28368
 
 
28369
/* Formatting function pointers is tricky: there is no standard pointer for
 
28370
 * function pointers and the size of a function pointer may depend on the
 
28371
 * specific pointer type.  This helper formats a function pointer based on
 
28372
 * its memory layout to get something useful on most platforms.
 
28373
 */
 
28374
void duk_debug_format_funcptr(char *buf, int buf_size, unsigned char *fptr, int fptr_size) {
 
28375
        int i;
 
28376
        char *p = buf;
 
28377
        char *p_end = buf + buf_size - 1;
 
28378
 
 
28379
        DUK_MEMZERO(buf, buf_size);
 
28380
 
 
28381
        for (i = 0; i < fptr_size; i++) {
 
28382
                int left = p_end - p;
 
28383
                unsigned char ch;
 
28384
                if (left <= 0) {
 
28385
                        break;
 
28386
                }
 
28387
 
 
28388
                /* Quite approximate but should be useful for little and big endian. */
 
28389
#ifdef DUK_USE_INTEGER_BE
 
28390
                ch = fptr[i];
 
28391
#else
 
28392
                ch = fptr[fptr_size - 1 - i];
 
28393
#endif
 
28394
                p += DUK_SNPRINTF(p, left, "%02x", (int) ch);
 
28395
        }       
 
28396
}
 
28397
 
 
28398
#endif  /* DUK_USE_DEBUG */
 
28399
 
 
28400
#line 1 "duk_error_augment.c"
 
28401
/*
 
28402
 *  Augmenting errors at their creation site and their throw site.
 
28403
 *
 
28404
 *  When errors are created, traceback data is added by built-in code
 
28405
 *  and a user error handler (if defined) can process or replace the
 
28406
 *  error.  Similarly, when errors are thrown, a user error handler
 
28407
 *  (if defined) can process or replace the error.
 
28408
 *
 
28409
 *  Augmentation and other processing at error creation time is nice
 
28410
 *  because an error is only created once, but it may be thrown and
 
28411
 *  rethrown multiple times.  User error handler registered for processing
 
28412
 *  an error at its throw site must be careful to handle rethrowing in
 
28413
 *  a useful manner.
 
28414
 *
 
28415
 *  Error augmentation may throw an internal error (e.g. alloc error).
 
28416
 *
 
28417
 *  Ecmascript allows throwing any values, so all values cannot be
 
28418
 *  augmented.  Currently, the built-in augmentation at error creation
 
28419
 *  only augments error values which are Error instances (= have the
 
28420
 *  built-in Error.prototype in their prototype chain) and are also
 
28421
 *  extensible.  User error handlers have no limitations in this respect.
 
28422
 */
 
28423
 
 
28424
/* include removed: duk_internal.h */
 
28425
 
 
28426
/*
 
28427
 *  Helper for calling a user error handler.
 
28428
 *
 
28429
 *  'thr' must be the currently active thread; the error handler is called
 
28430
 *  in its context.  The valstack of 'thr' must have the error value on
 
28431
 *  top, and will be replaced by another error value based on the return
 
28432
 *  value of the error handler.
 
28433
 *
 
28434
 *  The helper calls duk_handle_call() recursively in protected mode.
 
28435
 *  Before that call happens, no longjmps should happen; as a consequence,
 
28436
 *  we must assume that the valstack contains enough temporary space for
 
28437
 *  arguments and such.
 
28438
 *
 
28439
 *  While the error handler runs, any errors thrown will not trigger a
 
28440
 *  recursive error handler call (this is implemented using a heap level
 
28441
 *  flag which will "follow" through any coroutines resumed inside the
 
28442
 *  error handler).  If the error handler is not callable or throws an
 
28443
 *  error, the resulting error replaces the original error (for Duktape
 
28444
 *  internal errors, duk_error_throw.c further substitutes this error with
 
28445
 *  a DoubleError which is not ideal).  This would be easy to change and
 
28446
 *  even signal to the caller.
 
28447
 *
 
28448
 *  The user error handler is stored in 'Duktape.errcreate' or
 
28449
 *  'Duktape.errthrow' depending on whether we're augmenting the error at
 
28450
 *  creation or throw time.  There are several alternatives to this approach,
 
28451
 *  see doc/error-objects.txt for discussion.
 
28452
 *
 
28453
 *  Note: since further longjmp()s may occur while calling the error handler
 
28454
 *  (for many reasons, e.g. a labeled 'break' inside the handler), the
 
28455
 *  caller can make no assumptions on the thr->heap->lj state after the
 
28456
 *  call (this affects especially duk_error_throw.c).  This is not an issue
 
28457
 *  as long as the caller writes to the lj state only after the error handler
 
28458
 *  finishes.
 
28459
 */
 
28460
 
 
28461
#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
 
28462
static void duk__err_augment_user(duk_hthread *thr, int stridx_cb) {
 
28463
        duk_context *ctx = (duk_context *) thr;
 
28464
        duk_tval *tv_hnd;
 
28465
        int call_flags;
 
28466
        int rc;
 
28467
 
 
28468
        DUK_ASSERT(thr != NULL);
 
28469
        DUK_ASSERT(thr->heap != NULL);
 
28470
        DUK_ASSERT(stridx_cb >= 0 && stridx_cb < DUK_HEAP_NUM_STRINGS);
 
28471
 
 
28472
        if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
 
28473
                DUK_DDPRINT("recursive call to error handler, ignore");
 
28474
                return;
 
28475
        }
 
28476
 
 
28477
        /*
 
28478
         *  Check whether or not we have an error handler.
 
28479
         *
 
28480
         *  We must be careful of not triggering an error when looking up the
 
28481
         *  property.  For instance, if the property is a getter, we don't want
 
28482
         *  to call it, only plain values are allowed.  The value, if it exists,
 
28483
         *  is not checked.  If the value is not a function, a TypeError happens
 
28484
         *  when it is called and that error replaces the original one.
 
28485
         */
 
28486
 
 
28487
        DUK_ASSERT_VALSTACK_SPACE(thr, 4);  /* 3 entries actually needed below */
 
28488
 
 
28489
        /* [ ... errval ] */
 
28490
 
 
28491
        if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
 
28492
                /* When creating built-ins, some of the built-ins may not be set
 
28493
                 * and we want to tolerate that when throwing errors.
 
28494
                 */
 
28495
                DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring");
 
28496
                return;
 
28497
        }
 
28498
        tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->builtins[DUK_BIDX_DUKTAPE],
 
28499
                                                          thr->strs[stridx_cb]);
 
28500
        if (tv_hnd == NULL) {
 
28501
                DUK_DDPRINT("error handler does not exist or is not a plain value: %!T", tv_hnd);
 
28502
                return;
 
28503
        }
 
28504
        DUK_DDDPRINT("error handler dump (callability not checked): %!T", tv_hnd);
 
28505
        duk_push_tval(ctx, tv_hnd);
 
28506
 
 
28507
        /* [ ... errval errhandler ] */
 
28508
 
 
28509
        duk_insert(ctx, -2);  /* -> [ ... errhandler errval ] */
 
28510
        duk_push_undefined(ctx);
 
28511
        duk_insert(ctx, -2);  /* -> [ ... errhandler undefined(= this) errval ] */
 
28512
 
 
28513
        /* [ ... errhandler undefined errval ] */
 
28514
 
 
28515
        /*
 
28516
         *  DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
 
28517
         *  recursion depth limit (and won't increase it either).  This is
 
28518
         *  dangerous, but useful because it allows the error handler to run
 
28519
         *  even if the original error is caused by C recursion depth limit.
 
28520
         *
 
28521
         *  The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
 
28522
         *  duration of the error handler and cleared afterwards.  This flag
 
28523
         *  prevents the error handler from running recursively.  The flag is
 
28524
         *  heap level so that the flag properly controls even coroutines
 
28525
         *  launched by an error handler.  Since the flag is heap level, it is
 
28526
         *  critical to restore it correctly.
 
28527
         *
 
28528
         *  We ignore errors now: a success return and an error value both
 
28529
         *  replace the original error value.  (This would be easy to change.)
 
28530
         */
 
28531
 
 
28532
        DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));  /* since no recursive error handler calls */
 
28533
        DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
 
28534
 
 
28535
        call_flags = DUK_CALL_FLAG_PROTECTED |
 
28536
                     DUK_CALL_FLAG_IGNORE_RECLIMIT;  /* protected, ignore reclimit, not constructor */
 
28537
 
 
28538
        rc = duk_handle_call(thr,
 
28539
                             1,            /* num args */
 
28540
                             call_flags);  /* call_flags */
 
28541
        DUK_UNREF(rc);  /* no need to check now: both success and error are OK */
 
28542
 
 
28543
        DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
 
28544
        DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
 
28545
 
 
28546
        /* [ ... errval ] */
 
28547
}
 
28548
#endif  /* DUK_USE_ERRTHROW || DUK_USE_ERRHANDLE */
 
28549
 
 
28550
/*
 
28551
 *  Add tracedata to an error on the stack top.
 
28552
 */
 
28553
 
 
28554
#ifdef DUK_USE_TRACEBACKS
 
28555
static void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, int line, int noblame_fileline) {
 
28556
        duk_context *ctx = (duk_context *) thr;
 
28557
        int depth;
 
28558
        int i, i_min;
 
28559
        int arr_idx;
 
28560
        double d;
 
28561
 
 
28562
        DUK_ASSERT(thr != NULL);
 
28563
        DUK_ASSERT(thr_callstack != NULL);
 
28564
        DUK_ASSERT(ctx != NULL);
 
28565
 
 
28566
        /* [ ... error ] */
 
28567
 
 
28568
        /*
 
28569
         *  The traceback format is pretty arcane in an attempt to keep it compact
 
28570
         *  and cheap to create.  It may change arbitrarily from version to version.
 
28571
         *  It should be decoded/accessed through version specific accessors only.
 
28572
         *
 
28573
         *  See doc/error-objects.txt.
 
28574
         */
 
28575
 
 
28576
        DUK_DDDPRINT("adding traceback to object: %!T", duk_get_tval(ctx, -1));
 
28577
 
 
28578
        duk_push_array(ctx);  /* XXX: specify array size, as we know it */
 
28579
        arr_idx = 0;
 
28580
 
 
28581
        /* filename/line from C macros (__FILE__, __LINE__) are added as an
 
28582
         * entry with a special format: (string, number).  The number contains
 
28583
         * the line and flags.
 
28584
         */
 
28585
 
 
28586
        /* FIXME: optimize: allocate an array part to the necessary size (upwards
 
28587
         * estimate) and fill in the values directly into the array part; finally
 
28588
         * update 'length'.
 
28589
         */
 
28590
 
 
28591
        /* FIXME: using duk_put_prop_index() would cause obscure error cases when Array.prototype
 
28592
         * has write-protected array index named properties.  This was seen as DoubleErrors
 
28593
         * in e.g. some test262 test cases.  Using duk_def_prop_index() is better but currently
 
28594
         * there is no fast path variant for that; the current implementation interns the array
 
28595
         * index as a string.  This can be fixed directly, or perhaps the traceback can be fixed
 
28596
         * altogether to fill in the tracedata directly into the array part.
 
28597
         */
 
28598
 
 
28599
        /* [ ... error arr ] */
 
28600
 
 
28601
        if (filename) {
 
28602
                duk_push_string(ctx, filename);
 
28603
                duk_def_prop_index(ctx, -2, arr_idx, DUK_PROPDESC_FLAGS_WEC);
 
28604
                arr_idx++;
 
28605
 
 
28606
                d = (noblame_fileline ? ((double) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
 
28607
                    (double) line;
 
28608
                duk_push_number(ctx, d);
 
28609
                duk_def_prop_index(ctx, -2, arr_idx, DUK_PROPDESC_FLAGS_WEC);
 
28610
                arr_idx++;
 
28611
        }
 
28612
 
 
28613
        /* traceback depth doesn't take into account the filename/line
 
28614
         * special handling above (intentional)
 
28615
         */
 
28616
        depth = DUK_USE_TRACEBACK_DEPTH;
 
28617
        i_min = (thr_callstack->callstack_top > (size_t) depth ? (int) (thr_callstack->callstack_top - depth) : 0);
 
28618
        DUK_ASSERT(i_min >= 0);
 
28619
 
 
28620
        /* [ ... error arr ] */
 
28621
 
 
28622
        for (i = thr_callstack->callstack_top - 1; i >= i_min; i--) {
 
28623
                int pc;
 
28624
 
 
28625
                /*
 
28626
                 *  Note: each API operation potentially resizes the callstack,
 
28627
                 *  so be careful to re-lookup after every operation.  Currently
 
28628
                 *  these is no issue because we don't store a temporary 'act'
 
28629
                 *  pointer at all.  (This would be a non-issue if we operated
 
28630
                 *  directly on the array part.)
 
28631
                 */
 
28632
 
 
28633
                /* [... arr] */
 
28634
 
 
28635
                DUK_ASSERT(thr_callstack->callstack[i].func != NULL);
 
28636
                DUK_ASSERT(thr_callstack->callstack[i].pc >= 0);
 
28637
 
 
28638
                /* add function */
 
28639
                duk_push_hobject(ctx, thr_callstack->callstack[i].func);  /* -> [... arr func] */
 
28640
                duk_def_prop_index(ctx, -2, arr_idx, DUK_PROPDESC_FLAGS_WEC);
 
28641
                arr_idx++;
 
28642
 
 
28643
                /* add a number containing: pc, activation flags */
 
28644
 
 
28645
                /* Add a number containing: pc, activation flag
 
28646
                 *
 
28647
                 * PC points to next instruction, find offending PC.  Note that
 
28648
                 * PC == 0 for native code.
 
28649
                 */
 
28650
                pc = thr_callstack->callstack[i].pc;
 
28651
                if (pc > 0) {
 
28652
                        pc--;
 
28653
                }
 
28654
                DUK_ASSERT(pc >= 0 && (double) pc < DUK_DOUBLE_2TO32);  /* assume PC is at most 32 bits and non-negative */
 
28655
                d = ((double) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (double) pc;
 
28656
                duk_push_number(ctx, d);  /* -> [... arr num] */
 
28657
                duk_def_prop_index(ctx, -2, arr_idx, DUK_PROPDESC_FLAGS_WEC);
 
28658
                arr_idx++;
 
28659
        }
 
28660
 
 
28661
        /* FIXME: set with duk_hobject_set_length() when tracedata is filled directly */
 
28662
        duk_push_int(ctx, (int) arr_idx);
 
28663
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
 
28664
 
 
28665
        /* [ ... error arr ] */
 
28666
 
 
28667
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_TRACEDATA, DUK_PROPDESC_FLAGS_WEC);  /* -> [ ... error ] */
 
28668
}
 
28669
#endif  /* DUK_USE_TRACEBACKS */
 
28670
 
 
28671
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
 
28672
static void duk__err_augment_builtin_throw(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, int line, int noblame_fileline, duk_hobject *obj) {
 
28673
        duk_context *ctx = (duk_context *) thr;
 
28674
#ifdef DUK_USE_ASSERTIONS
 
28675
        duk_int_t entry_top;
 
28676
#endif
 
28677
 
 
28678
#ifdef DUK_USE_ASSERTIONS
 
28679
        entry_top = duk_get_top(ctx);
 
28680
#endif
 
28681
        DUK_ASSERT(obj != NULL);
 
28682
 
 
28683
        DUK_UNREF(obj);  /* unreferenced w/o tracebacks */
 
28684
        DUK_UNREF(ctx);  /* unreferenced w/ tracebacks */
 
28685
 
 
28686
#ifdef DUK_USE_TRACEBACKS
 
28687
        /*
 
28688
         *  If tracebacks are enabled, the 'tracedata' property is the only
 
28689
         *  thing we need: 'fileName' and 'lineNumber' are virtual properties
 
28690
         *  which use 'tracedata'.
 
28691
         */
 
28692
 
 
28693
        if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_TRACEDATA(thr))) {
 
28694
                DUK_DDDPRINT("error value already has a 'tracedata' property, not modifying it");
 
28695
        } else {
 
28696
                duk__add_traceback(thr, thr_callstack, filename, line, noblame_fileline);
 
28697
        }
 
28698
#else
 
28699
        /*
 
28700
         *  If tracebacks are disabled, 'fileName' and 'lineNumber' are added
 
28701
         *  as plain own properties.  Since Error.prototype has accessors of
 
28702
         *  the same name, we need to define own properties directly (cannot
 
28703
         *  just use e.g. duk_put_prop_stridx).  Existing properties are not
 
28704
         *  overwritten in case they already exist.
 
28705
         */
 
28706
 
 
28707
        if (filename && !noblame_fileline) {
 
28708
                /* FIXME: file/line is disabled in minimal builds, so disable this too
 
28709
                 * when appropriate.
 
28710
                 */
 
28711
                duk_push_string(ctx, filename);
 
28712
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
 
28713
                duk_push_int(ctx, line);
 
28714
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
 
28715
        } else if (thr_callstack->callstack_top > 0) {
 
28716
                duk_activation *act;
 
28717
                duk_hobject *func;
 
28718
                duk_hbuffer *pc2line;
 
28719
 
 
28720
                act = thr_callstack->callstack + thr_callstack->callstack_top - 1;
 
28721
                DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
 
28722
                func = act->func;
 
28723
                if (func) {
 
28724
                        int pc;
 
28725
                        duk_uint32_t line;
 
28726
 
 
28727
                        /* PC points to next instruction, find offending PC.  Note that
 
28728
                         * PC == 0 for native code.
 
28729
                         */
 
28730
                        pc = act->pc;
 
28731
                        if (pc > 0) {
 
28732
                                pc--;
 
28733
                        }
 
28734
                        DUK_ASSERT(pc >= 0 && (double) pc < DUK_DOUBLE_2TO32);  /* assume PC is at most 32 bits and non-negative */
 
28735
                        act = NULL;  /* invalidated by pushes, so get out of the way */
 
28736
 
 
28737
                        duk_push_hobject(ctx, func);
 
28738
 
 
28739
                        /* [ ... error func ] */
 
28740
 
 
28741
                        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
 
28742
                        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
 
28743
                        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
28744
#if 0
 
28745
                                duk_push_number(ctx, pc);
 
28746
                                duk_def_prop_stridx(ctx, -3, DUK_STRIDX_PC, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAGS_NO_OVERWRITE);
 
28747
#endif
 
28748
 
 
28749
                                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_PC2LINE);
 
28750
                                if (duk_is_buffer(ctx, -1)) {
 
28751
                                        pc2line = duk_get_hbuffer(ctx, -1);
 
28752
                                        DUK_ASSERT(pc2line != NULL);
 
28753
                                        DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(pc2line));
 
28754
                                        line = duk_hobject_pc2line_query((duk_hbuffer_fixed *) pc2line, (duk_uint_fast32_t) pc);
 
28755
                                        duk_push_number(ctx, (double) line); /* -> [ ... error func pc2line line ] */  /* FIXME: u32 */
 
28756
                                        duk_def_prop_stridx(ctx, -4, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
 
28757
                                }
 
28758
                                duk_pop(ctx);
 
28759
                        } else {
 
28760
                                /* Native function, no relevant lineNumber. */
 
28761
                        }
 
28762
 
 
28763
                        duk_pop(ctx);
 
28764
                }
 
28765
        }
 
28766
#endif  /* DUK_USE_TRACEBACKS */
 
28767
 
 
28768
#ifdef DUK_USE_ASSERTIONS
 
28769
        DUK_ASSERT(duk_get_top(ctx) == entry_top);
 
28770
#endif
 
28771
}
 
28772
#endif  /* DUK_USE_AUGMENT_ERROR_CREATE */
 
28773
 
 
28774
/*
 
28775
 *  Augment an error at creation time with tracedata/fileName/lineNumber
 
28776
 *  and allow a user error handler (if defined) to process/replace the error.
 
28777
 *  The error to be augmented is at the stack top.
 
28778
 *
 
28779
 *  thr: thread containing the error value
 
28780
 *  thr_callstack: thread which should be used for generating callstack etc.
 
28781
 *  filename: C __FILE__ related to the error
 
28782
 *  line: C __LINE__ related to the error
 
28783
 *  noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
 
28784
 *                    (needed because user code filename/line are reported but internal ones
 
28785
 *                    are not)
 
28786
 *
 
28787
 *  FIXME: rename noblame_fileline to flags field; combine it to some existing
 
28788
 *  field (there are only a few call sites so this may not be worth it).
 
28789
 */
 
28790
 
 
28791
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
 
28792
void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, int line, int noblame_fileline) {
 
28793
        duk_context *ctx = (duk_context *) thr;
 
28794
        duk_hobject *obj;
 
28795
 
 
28796
        DUK_ASSERT(thr != NULL);
 
28797
        DUK_ASSERT(thr_callstack != NULL);
 
28798
        DUK_ASSERT(ctx != NULL);
 
28799
 
 
28800
        /* [ ... error ] */
 
28801
 
 
28802
        /*
 
28803
         *  Criteria for augmenting:
 
28804
         *
 
28805
         *   - augmentation enabled in build (naturally)
 
28806
         *   - error value internal prototype chain contains the built-in
 
28807
         *     Error prototype object (i.e. 'val instanceof Error')
 
28808
         *
 
28809
         *  Additional criteria for built-in augmenting:
 
28810
         *
 
28811
         *   - error value is an extensible object
 
28812
         */
 
28813
 
 
28814
        obj = duk_get_hobject(ctx, -1);
 
28815
        if (!obj) {
 
28816
                DUK_DDDPRINT("value is not an object, skip both built-in and user augment");
 
28817
                return;
 
28818
        }
 
28819
        if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE])) {
 
28820
                DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment");
 
28821
                return;
 
28822
        }
 
28823
 
 
28824
        if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
 
28825
                DUK_DDDPRINT("error meets criteria, built-in augment");
 
28826
                duk__err_augment_builtin_throw(thr, thr_callstack, filename, line, noblame_fileline, obj);
 
28827
        } else {
 
28828
                DUK_DDDPRINT("error does not meet criteria, no built-in augment");
 
28829
        }
 
28830
 
 
28831
        /* [ ... error ] */
 
28832
 
 
28833
#if defined(DUK_USE_ERRCREATE)
 
28834
        duk__err_augment_user(thr, DUK_STRIDX_ERRCREATE);
 
28835
#endif
 
28836
}
 
28837
#endif  /* DUK_USE_AUGMENT_ERROR_CREATE */
 
28838
 
 
28839
/*
 
28840
 *  Augment an error at throw time; allow a user error handler (if defined)
 
28841
 *  to process/replace the error.  The error to be augmented is at the
 
28842
 *  stack top.
 
28843
 */
 
28844
 
 
28845
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
28846
void duk_err_augment_error_throw(duk_hthread *thr) {
 
28847
#if defined(DUK_USE_ERRTHROW)
 
28848
        duk__err_augment_user(thr, DUK_STRIDX_ERRTHROW);
 
28849
#endif  /* DUK_USE_ERRTHROW */
 
28850
}
 
28851
#endif  /* DUK_USE_AUGMENT_ERROR_THROW */
 
28852
#line 1 "duk_error_longjmp.c"
 
28853
/*
 
28854
 *  Do a longjmp call, calling the fatal error handler if no
 
28855
 *  catchpoint exists.
 
28856
 */
 
28857
 
 
28858
/* include removed: duk_internal.h */
 
28859
 
 
28860
void duk_err_longjmp(duk_hthread *thr) {
 
28861
        DUK_ASSERT(thr != NULL);
 
28862
 
 
28863
        if (!thr->heap->lj.jmpbuf_ptr) {
 
28864
                /*
 
28865
                 *  If we don't have a jmpbuf_ptr, there is little we can do
 
28866
                 *  except panic.  The caller's expectation is that we never
 
28867
                 *  return.
 
28868
                 */
 
28869
 
 
28870
                duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
 
28871
                DUK_UNREACHABLE();
 
28872
        }
 
28873
 
 
28874
        DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb, DUK_LONGJMP_DUMMY_VALUE);
 
28875
        DUK_UNREACHABLE();
 
28876
}
 
28877
 
 
28878
#line 1 "duk_error_macros.c"
 
28879
/*
 
28880
 *  Error, fatal, and panic handling.
 
28881
 */
 
28882
 
 
28883
/* include removed: duk_internal.h */
 
28884
 
 
28885
#define DUK__ERRFMT_BUFSIZE  256  /* size for formatting buffers */
 
28886
 
 
28887
#ifdef DUK_USE_VERBOSE_ERRORS
 
28888
 
 
28889
#ifdef DUK_USE_VARIADIC_MACROS
 
28890
void duk_err_handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...) {
 
28891
        va_list ap;
 
28892
        char msg[DUK__ERRFMT_BUFSIZE];
 
28893
        va_start(ap, fmt);
 
28894
        (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
 
28895
        msg[sizeof(msg) - 1] = (char) 0;
 
28896
        duk_err_create_and_throw(thr, code, msg, filename, line);
 
28897
        va_end(ap);  /* dead code, but ensures portability (see Linux man page notes) */
 
28898
}
 
28899
#else  /* DUK_USE_VARIADIC_MACROS */
 
28900
const char *duk_err_file_stash = NULL;
 
28901
int duk_err_line_stash = 0;
 
28902
 
 
28903
DUK_NORETURN(static void duk__handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, va_list ap));
 
28904
 
 
28905
static void duk__handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, va_list ap) {
 
28906
        char msg[DUK__ERRFMT_BUFSIZE];
 
28907
        (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
 
28908
        msg[sizeof(msg) - 1] = (char) 0;
 
28909
        duk_err_create_and_throw(thr, code, msg, filename, line);
 
28910
}
 
28911
 
 
28912
void duk_err_handle_error(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...) {
 
28913
        va_list ap;
 
28914
        va_start(ap, fmt);
 
28915
        duk__handle_error(filename, line, thr, code, fmt, ap);
 
28916
        va_end(ap);  /* dead code */
 
28917
}
 
28918
 
 
28919
void duk_err_handle_error_stash(duk_hthread *thr, int code, const char *fmt, ...) {
 
28920
        va_list ap;
 
28921
        va_start(ap, fmt);
 
28922
        duk__handle_error(duk_err_file_stash, duk_err_line_stash, thr, code, fmt, ap);
 
28923
        va_end(ap);  /* dead code */
 
28924
}
 
28925
#endif  /* DUK_USE_VARIADIC_MACROS */
 
28926
 
 
28927
#else  /* DUK_USE_VERBOSE_ERRORS */
 
28928
 
 
28929
#ifdef DUK_USE_VARIADIC_MACROS
 
28930
void duk_err_handle_error(duk_hthread *thr, int code) {
 
28931
        duk_err_create_and_throw(thr, code);
 
28932
}
 
28933
 
 
28934
#else  /* DUK_USE_VARIADIC_MACROS */
 
28935
void duk_err_handle_error_nonverbose1(duk_hthread *thr, int code, const char *fmt, ...) {
 
28936
        duk_err_create_and_throw(thr, code);
 
28937
}
 
28938
 
 
28939
void duk_err_handle_error_nonverbose2(const char *filename, int line, duk_hthread *thr, int code, const char *fmt, ...) {
 
28940
        duk_err_create_and_throw(thr, code);
 
28941
}
 
28942
#endif  /* DUK_USE_VARIADIC_MACROS */
 
28943
 
 
28944
#endif  /* DUK_USE_VERBOSE_ERRORS */
 
28945
 
 
28946
/*
 
28947
 *  Default fatal error handler
 
28948
 */
 
28949
 
 
28950
void duk_default_fatal_handler(duk_context *ctx, int code, const char *msg) {
 
28951
        DUK_UNREF(ctx);
 
28952
#ifdef DUK_USE_FILE_IO
 
28953
        DUK_FPRINTF(DUK_STDERR, "FATAL %d: %s\n", code, msg ? msg : "null");
 
28954
        DUK_FFLUSH(DUK_STDERR);
 
28955
#else
 
28956
        /* omit print */
 
28957
#endif
 
28958
        DUK_DPRINT("default fatal handler called, code %d -> calling DUK_PANIC()", code);
 
28959
        DUK_PANIC(code, msg);
 
28960
        DUK_UNREACHABLE();
 
28961
}
 
28962
 
 
28963
/*
 
28964
 *  Default panic handler
 
28965
 */
 
28966
 
 
28967
#if !defined(DUK_USE_PANIC_HANDLER)
 
28968
void duk_default_panic_handler(int code, const char *msg) {
 
28969
#ifdef DUK_USE_FILE_IO
 
28970
        DUK_FPRINTF(DUK_STDERR, "PANIC %d: %s ("
 
28971
#if defined(DUK_USE_PANIC_ABORT)
 
28972
                    "calling abort"
 
28973
#elif defined(DUK_USE_PANIC_EXIT)
 
28974
                    "calling exit"
 
28975
#elif defined(DUK_USE_PANIC_SEGFAULT)
 
28976
                    "segfaulting on purpose"
 
28977
#else
 
28978
#error no DUK_USE_PANIC_xxx macro defined
 
28979
#endif  
 
28980
                    ")\n", code, msg ? msg : "null");
 
28981
        DUK_FFLUSH(DUK_STDERR);
 
28982
#else
 
28983
        /* omit print */
 
28984
#endif
 
28985
 
 
28986
#if defined(DUK_USE_PANIC_ABORT)
 
28987
        DUK_ABORT();
 
28988
#elif defined(DUK_USE_PANIC_EXIT)
 
28989
        DUK_EXIT(-1);
 
28990
#elif defined(DUK_USE_PANIC_SEGFAULT)
 
28991
        /* exit() afterwards to satisfy "noreturn" */
 
28992
        DUK_CAUSE_SEGFAULT();
 
28993
        DUK_EXIT(-1);
 
28994
#else
 
28995
#error no DUK_USE_PANIC_xxx macro defined
 
28996
#endif
 
28997
 
 
28998
        DUK_UNREACHABLE();
 
28999
}
 
29000
#endif  /* !DUK_USE_PANIC_HANDLER */
 
29001
 
 
29002
#undef DUK__ERRFMT_BUFSIZE
 
29003
#line 1 "duk_error_misc.c"
 
29004
/*
 
29005
 *  Error helpers
 
29006
 */
 
29007
 
 
29008
/* include removed: duk_internal.h */
 
29009
 
 
29010
/*
 
29011
 *  Get prototype object for an integer error code.
 
29012
 */
 
29013
 
 
29014
duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, int err_code) {
 
29015
        switch (err_code) {
 
29016
        case DUK_ERR_EVAL_ERROR:
 
29017
                return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
 
29018
        case DUK_ERR_RANGE_ERROR:
 
29019
                return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
 
29020
        case DUK_ERR_REFERENCE_ERROR:
 
29021
                return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
 
29022
        case DUK_ERR_SYNTAX_ERROR:
 
29023
                return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
 
29024
        case DUK_ERR_TYPE_ERROR:
 
29025
                return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
 
29026
        case DUK_ERR_URI_ERROR:
 
29027
                return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
 
29028
 
 
29029
        /* XXX: more specific error classes? */
 
29030
        case DUK_ERR_UNIMPLEMENTED_ERROR:
 
29031
        case DUK_ERR_INTERNAL_ERROR:
 
29032
        case DUK_ERR_ALLOC_ERROR:
 
29033
        case DUK_ERR_ASSERTION_ERROR:
 
29034
        case DUK_ERR_API_ERROR:
 
29035
        case DUK_ERR_ERROR:
 
29036
        default:
 
29037
                return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
 
29038
        }
 
29039
}
 
29040
 
 
29041
/*
 
29042
 *  Exposed helper for setting up heap longjmp state.
 
29043
 */
 
29044
 
 
29045
void duk_err_setup_heap_ljstate(duk_hthread *thr, int lj_type) {
 
29046
        duk_tval tv_tmp;
 
29047
 
 
29048
        thr->heap->lj.type = lj_type;
 
29049
 
 
29050
        DUK_ASSERT(thr->valstack_top > thr->valstack);
 
29051
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
29052
        DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, thr->valstack_top - 1);
 
29053
        DUK_TVAL_INCREF(thr, &thr->heap->lj.value1);
 
29054
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
29055
 
 
29056
        duk_pop((duk_context *) thr);
 
29057
}
 
29058
#line 1 "duk_error_throw.c"
 
29059
/*
 
29060
 *  Create and throw an Ecmascript error object based on a code and a message.
 
29061
 *
 
29062
 *  Used when we throw errors internally.  Ecmascript generated error objects
 
29063
 *  are created by Ecmascript code, and the throwing is handled by the bytecode
 
29064
 *  executor.
 
29065
 */
 
29066
 
 
29067
/* include removed: duk_internal.h */
 
29068
 
 
29069
/*
 
29070
 *  Create and throw an error (originating from Duktape internally)
 
29071
 *
 
29072
 *  Push an error object on top of the stack, possibly throw augmenting
 
29073
 *  the error, and finally longjmp.
 
29074
 *
 
29075
 *  If an error occurs while we're dealing with the current error, we might
 
29076
 *  enter an infinite recursion loop.  This is prevented by detecting a
 
29077
 *  "double fault" through the heap->handling_error flag; the recursion
 
29078
 *  then stops at the second level.
 
29079
 */
 
29080
 
 
29081
#ifdef DUK_USE_VERBOSE_ERRORS
 
29082
void duk_err_create_and_throw(duk_hthread *thr, duk_uint32_t code, const char *msg, const char *filename, int line) {
 
29083
#else
 
29084
void duk_err_create_and_throw(duk_hthread *thr, duk_uint32_t code) {
 
29085
#endif
 
29086
        duk_context *ctx = (duk_context *) thr;
 
29087
        int double_error = thr->heap->handling_error;
 
29088
 
 
29089
#ifdef DUK_USE_VERBOSE_ERRORS
 
29090
        DUK_DDPRINT("duk_err_create_and_throw(): code=%d, msg=%s, filename=%s, line=%d",
 
29091
                     code, msg ? msg : "null", filename ? filename : "null", line);
 
29092
#else
 
29093
        DUK_DDPRINT("duk_err_create_and_throw(): code=%d", code);
 
29094
#endif
 
29095
 
 
29096
        DUK_ASSERT(thr != NULL);
 
29097
        DUK_ASSERT(ctx != NULL);
 
29098
 
 
29099
        thr->heap->handling_error = 1;
 
29100
 
 
29101
        /*
 
29102
         *  Create and push an error object onto the top of stack.
 
29103
         *  If a "double error" occurs, use a fixed error instance
 
29104
         *  to avoid further trouble.
 
29105
         */
 
29106
 
 
29107
        /* FIXME: if attempt to push beyond allocated valstack, this double fault
 
29108
         * handling fails miserably.  We should really write the double error
 
29109
         * directly to thr->heap->lj.value1 and avoid valstack use entirely.
 
29110
         */
 
29111
 
 
29112
        if (double_error) {
 
29113
                if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
 
29114
                        DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance");
 
29115
                        duk_push_hobject(ctx, thr->builtins[DUK_BIDX_DOUBLE_ERROR]);
 
29116
                } else {
 
29117
                        DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
 
29118
                                   "-> push the error code as a number");
 
29119
                        duk_push_int(ctx, code);
 
29120
                }
 
29121
        } else {
 
29122
                /* Error object is augmented at its creation here. */
 
29123
                duk_require_stack(ctx, 1);
 
29124
                /* FIXME: unnecessary '%s' formatting here */
 
29125
#ifdef DUK_USE_VERBOSE_ERRORS
 
29126
                duk_push_error_object_raw(ctx,
 
29127
                                          code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
 
29128
                                          filename,
 
29129
                                          line,
 
29130
                                          "%s",
 
29131
                                          msg);
 
29132
#else
 
29133
                duk_push_error_object_raw(ctx,
 
29134
                                          code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
 
29135
                                          NULL,
 
29136
                                          0,
 
29137
                                          NULL);
 
29138
#endif
 
29139
        }
 
29140
 
 
29141
        /*
 
29142
         *  Augment error (throw time), unless alloc/double error
 
29143
         */
 
29144
 
 
29145
        if (double_error || code == DUK_ERR_ALLOC_ERROR) {
 
29146
                DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble");
 
29147
        } else {
 
29148
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
29149
                DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)", duk_get_tval(ctx, -1));
 
29150
                duk_err_augment_error_throw(thr);
 
29151
#endif
 
29152
        }
 
29153
 
 
29154
        /*
 
29155
         *  Finally, longjmp
 
29156
         */
 
29157
 
 
29158
        thr->heap->handling_error = 0;
 
29159
 
 
29160
        duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
 
29161
 
 
29162
        DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
 
29163
                     &thr->heap->lj.value1, &thr->heap->lj.value2);
 
29164
 
 
29165
        duk_err_longjmp(thr);
 
29166
        DUK_UNREACHABLE();
 
29167
}
 
29168
 
 
29169
/*
 
29170
 *  Helper for C function call negative return values.
 
29171
 */
 
29172
 
 
29173
void duk_error_throw_from_negative_rc(duk_hthread *thr, int rc) {
 
29174
        duk_context *ctx = (duk_context *) thr;
 
29175
        const char *msg;
 
29176
        int code;
 
29177
 
 
29178
        DUK_ASSERT(thr != NULL);
 
29179
        DUK_ASSERT(rc < 0);
 
29180
 
 
29181
        /* FIXME: this generates quite large code - perhaps select the error
 
29182
         * class based on the code and then just use the error 'name'?
 
29183
         */
 
29184
 
 
29185
        code = -rc;
 
29186
 
 
29187
        switch (rc) {
 
29188
        case DUK_RET_UNIMPLEMENTED_ERROR:  msg = "unimplemented"; break;
 
29189
        case DUK_RET_UNSUPPORTED_ERROR:    msg = "unsupported"; break;
 
29190
        case DUK_RET_INTERNAL_ERROR:       msg = "internal"; break;
 
29191
        case DUK_RET_ALLOC_ERROR:          msg = "alloc"; break;
 
29192
        case DUK_RET_ASSERTION_ERROR:      msg = "assertion"; break;
 
29193
        case DUK_RET_API_ERROR:            msg = "api"; break;
 
29194
        case DUK_RET_UNCAUGHT_ERROR:       msg = "uncaught"; break;
 
29195
        case DUK_RET_ERROR:                msg = "error"; break;
 
29196
        case DUK_RET_EVAL_ERROR:           msg = "eval"; break;
 
29197
        case DUK_RET_RANGE_ERROR:          msg = "range"; break;
 
29198
        case DUK_RET_REFERENCE_ERROR:      msg = "reference"; break;
 
29199
        case DUK_RET_SYNTAX_ERROR:         msg = "syntax"; break;
 
29200
        case DUK_RET_TYPE_ERROR:           msg = "type"; break;
 
29201
        case DUK_RET_URI_ERROR:            msg = "uri"; break;
 
29202
        default:                           msg = "unknown"; break;
 
29203
        }
 
29204
 
 
29205
        DUK_ASSERT(msg != NULL);
 
29206
 
 
29207
        /*
 
29208
         *  The __FILE__ and __LINE__ information is intentionally not used in the
 
29209
         *  creation of the error object, as it isn't useful in the tracedata.  The
 
29210
         *  tracedata still contains the function which returned the negative return
 
29211
         *  code, and having the file/line of this function isn't very useful.
 
29212
         */
 
29213
 
 
29214
        duk_error_raw(ctx, code, NULL, 0, "%s error (rc %d)", msg, rc);
 
29215
        DUK_UNREACHABLE();
 
29216
}
 
29217
#line 1 "duk_hbuffer_alloc.c"
 
29218
/*
 
29219
 *  duk_hbuffer allocation and freeing.
 
29220
 */
 
29221
 
 
29222
/* include removed: duk_internal.h */
 
29223
 
 
29224
duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, size_t size, int dynamic) {
 
29225
        duk_hbuffer *res = NULL;
 
29226
        size_t alloc_size;
 
29227
 
 
29228
        DUK_DDDPRINT("allocate hbuffer");
 
29229
 
 
29230
        if (dynamic) {
 
29231
                alloc_size = sizeof(duk_hbuffer_dynamic);
 
29232
        } else {
 
29233
                alloc_size = sizeof(duk_hbuffer_fixed) + size;
 
29234
        }
 
29235
 
 
29236
#ifdef DUK_USE_ZERO_BUFFER_DATA
 
29237
        /* zero everything */
 
29238
        res = (duk_hbuffer *) DUK_ALLOC_ZEROED(heap, alloc_size);
 
29239
#else
 
29240
        res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
 
29241
#endif
 
29242
        if (!res) {
 
29243
                goto error;
 
29244
        }
 
29245
 
 
29246
#ifndef DUK_USE_ZERO_BUFFER_DATA
 
29247
        /* if no buffer zeroing, zero the header anyway */
 
29248
        DUK_MEMZERO((void *) res, dynamic ? sizeof(duk_hbuffer_dynamic) : sizeof(duk_hbuffer_fixed));
 
29249
#endif
 
29250
 
 
29251
        if (dynamic) {
 
29252
                duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
 
29253
                void *ptr;
 
29254
                if (size > 0) {
 
29255
                        DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer");
 
29256
#ifdef DUK_USE_ZERO_BUFFER_DATA
 
29257
                        ptr = DUK_ALLOC_ZEROED(heap, size);
 
29258
#else
 
29259
                        ptr = DUK_ALLOC(heap, size);  /* +1 for a safety nul term */
 
29260
#endif
 
29261
                        if (!ptr) {
 
29262
                                /* Because size > 0, NULL check is correct */
 
29263
                                goto error;
 
29264
                        }
 
29265
 
 
29266
                        h->curr_alloc = ptr;
 
29267
                        h->usable_size = size;  /* snug */
 
29268
                } else {
 
29269
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
29270
                        h->curr_alloc = NULL;
 
29271
#endif
 
29272
                        DUK_ASSERT(h->usable_size == 0);
 
29273
                }
 
29274
        }
 
29275
 
 
29276
        res->size = size;
 
29277
 
 
29278
        DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
 
29279
        if (dynamic) {
 
29280
                DUK_HBUFFER_SET_DYNAMIC(res);
 
29281
        }
 
29282
        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
 
29283
 
 
29284
        DUK_DDDPRINT("allocated hbuffer: %p", res);
 
29285
        return res;
 
29286
 
 
29287
 error:
 
29288
        DUK_DDPRINT("hbuffer allocation failed");
 
29289
 
 
29290
        DUK_FREE(heap, res);
 
29291
        return NULL;
 
29292
}
 
29293
 
 
29294
/* For indirect allocs. */
 
29295
 
 
29296
void *duk_hbuffer_get_dynalloc_ptr(void *ud) {
 
29297
        duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
 
29298
        return (void *) buf->curr_alloc;
 
29299
}
 
29300
 
 
29301
#line 1 "duk_hbuffer_ops.c"
 
29302
/*
 
29303
 *  duk_hbuffer operations such as resizing and inserting/appending data to
 
29304
 *  a dynamic buffer.
 
29305
 *
 
29306
 *  Append operations append to the end of the buffer and they are relatively
 
29307
 *  efficient: the buffer is grown with a "spare" part relative to the buffer
 
29308
 *  size to minimize reallocations.  Insert operations need to move existing
 
29309
 *  data forward in the buffer with memmove() and are not very efficient.
 
29310
 *  They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
 
29311
 */
 
29312
 
 
29313
/* include removed: duk_internal.h */
 
29314
 
 
29315
/*
 
29316
 *  Resizing
 
29317
 */
 
29318
 
 
29319
static size_t duk__add_spare(size_t size) {
 
29320
        size_t spare = (size / DUK_HBUFFER_SPARE_DIVISOR) + DUK_HBUFFER_SPARE_ADD;
 
29321
        size_t res;
 
29322
 
 
29323
        /* FIXME: handle corner cases where size is close to size limit (wraparound) */
 
29324
        res = size + spare;
 
29325
        DUK_ASSERT(res >= size);
 
29326
 
 
29327
        return res;
 
29328
}
 
29329
 
 
29330
void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t new_size, size_t new_usable_size) {
 
29331
        size_t new_alloc_size;
 
29332
        void *res;
 
29333
 
 
29334
        DUK_ASSERT(thr != NULL);
 
29335
        DUK_ASSERT(buf != NULL);
 
29336
        DUK_ASSERT(new_usable_size >= new_size);
 
29337
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29338
 
 
29339
        /*
 
29340
         *  Maximum size check
 
29341
         *
 
29342
         *  XXX: check against usable size?
 
29343
         */
 
29344
 
 
29345
        if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
 
29346
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "buffer too long");
 
29347
        }
 
29348
 
 
29349
        /*
 
29350
         *  Note: use indirect realloc variant just in case mark-and-sweep
 
29351
         *  (finalizers) might resize this same buffer during garbage
 
29352
         *  collection.
 
29353
         */
 
29354
 
 
29355
        new_alloc_size = new_usable_size;
 
29356
        res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_alloc_size);
 
29357
        if (res || new_alloc_size == 0) {
 
29358
                /* 'res' may be NULL if new allocation size is 0. */
 
29359
 
 
29360
                DUK_DDDPRINT("resized dynamic buffer %p:%d:%d -> %p:%d:%d",
 
29361
                             buf->curr_alloc, buf->size, buf->usable_size,
 
29362
                             res, new_size, new_usable_size);
 
29363
 
 
29364
                /*
 
29365
                 *  The entire allocated buffer area, regardless of actual used
 
29366
                 *  size, is kept zeroed in resizes for simplicity.  If the buffer
 
29367
                 *  is grown, zero the new part.  Another policy would be to
 
29368
                 *  ensure data is zeroed as the used part is extended.  The
 
29369
                 *  current approach is much more simple and is not a big deal
 
29370
                 *  because the spare part is relatively small.
 
29371
                 */
 
29372
 
 
29373
                if (new_alloc_size > buf->usable_size) {
 
29374
                        DUK_ASSERT(new_alloc_size - buf->usable_size > 0);
 
29375
#ifdef DUK_USE_ZERO_BUFFER_DATA
 
29376
                        DUK_MEMZERO((void *) ((char *) res + buf->usable_size),
 
29377
                                    new_alloc_size - buf->usable_size);
 
29378
#endif
 
29379
                }
 
29380
 
 
29381
                buf->size = new_size;
 
29382
                buf->usable_size = new_usable_size;
 
29383
                buf->curr_alloc = res;
 
29384
        } else {
 
29385
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to resize buffer from %d:%d to %d:%d",
 
29386
                          buf->size, buf->usable_size, new_size, new_usable_size);
 
29387
        }
 
29388
 
 
29389
        DUK_ASSERT(res != NULL || new_alloc_size == 0);
 
29390
}
 
29391
 
 
29392
void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
 
29393
        DUK_ASSERT(thr != NULL);
 
29394
        DUK_ASSERT(buf != NULL);
 
29395
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29396
 
 
29397
        duk_hbuffer_resize(thr, buf, 0, 0);
 
29398
}
 
29399
 
 
29400
void duk_hbuffer_compact(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
 
29401
        size_t curr_size;
 
29402
 
 
29403
        DUK_ASSERT(thr != NULL);
 
29404
        DUK_ASSERT(buf != NULL);
 
29405
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29406
 
 
29407
        curr_size = DUK_HBUFFER_GET_SIZE(buf);
 
29408
        duk_hbuffer_resize(thr, buf, curr_size, curr_size);
 
29409
}
 
29410
 
 
29411
/*
 
29412
 *  Inserts
 
29413
 */
 
29414
 
 
29415
void duk_hbuffer_insert_bytes(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint8_t *data, size_t length) {
 
29416
        char *p;
 
29417
 
 
29418
        /* XXX: allow inserts with offset > curr_size? i.e., insert zeroes automatically? */
 
29419
 
 
29420
        DUK_ASSERT(thr != NULL);
 
29421
        DUK_ASSERT(buf != NULL);
 
29422
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29423
        DUK_ASSERT_DISABLE(offset >= 0);  /* unsigned, so always true */
 
29424
        DUK_ASSERT(offset <= DUK_HBUFFER_GET_SIZE(buf));  /* equality is OK (= append) */
 
29425
        DUK_ASSERT(data != NULL);
 
29426
        DUK_ASSERT_DISABLE(length >= 0);  /* unsigned, so always true */
 
29427
 
 
29428
        if (length == 0) {
 
29429
                return;
 
29430
        }
 
29431
 
 
29432
        if (DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) < length) {
 
29433
                duk_hbuffer_resize(thr,
 
29434
                                   buf,
 
29435
                                   DUK_HBUFFER_GET_SIZE(buf),
 
29436
                                   duk__add_spare(DUK_HBUFFER_GET_SIZE(buf) + length));
 
29437
        }
 
29438
        DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) >= length);
 
29439
 
 
29440
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);
 
29441
        if (offset < DUK_HBUFFER_GET_SIZE(buf)) {
 
29442
                /* not an append */
 
29443
 
 
29444
                DUK_ASSERT(DUK_HBUFFER_GET_SIZE(buf) - offset > 0);  /* not a zero byte memmove */
 
29445
                DUK_MEMMOVE((void *) (p + offset + length),
 
29446
                            (void *) (p + offset),
 
29447
                            DUK_HBUFFER_GET_SIZE(buf) - offset);
 
29448
        }
 
29449
 
 
29450
        DUK_MEMCPY((void *) (p + offset),
 
29451
                   data,
 
29452
                   length);
 
29453
 
 
29454
        buf->size += length;
 
29455
}
 
29456
 
 
29457
void duk_hbuffer_insert_byte(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint8_t byte) {
 
29458
        DUK_ASSERT(thr != NULL);
 
29459
        DUK_ASSERT(buf != NULL);
 
29460
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29461
 
 
29462
        duk_hbuffer_insert_bytes(thr, buf, offset, &byte, 1);
 
29463
}
 
29464
 
 
29465
size_t duk_hbuffer_insert_cstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, const char *str) {
 
29466
        size_t len;
 
29467
 
 
29468
        DUK_ASSERT(thr != NULL);
 
29469
        DUK_ASSERT(buf != NULL);
 
29470
        DUK_ASSERT(str != NULL);
 
29471
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29472
 
 
29473
        len = DUK_STRLEN(str);
 
29474
        duk_hbuffer_insert_bytes(thr, buf, offset, (duk_uint8_t *) str, len);
 
29475
        return len;
 
29476
}
 
29477
 
 
29478
size_t duk_hbuffer_insert_hstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_hstring *str) {
 
29479
        size_t len;
 
29480
 
 
29481
        DUK_ASSERT(thr != NULL);
 
29482
        DUK_ASSERT(buf != NULL);
 
29483
        DUK_ASSERT(str != NULL);
 
29484
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29485
 
 
29486
        len = DUK_HSTRING_GET_BYTELEN(str);
 
29487
        duk_hbuffer_insert_bytes(thr, buf, offset, (duk_uint8_t *) DUK_HSTRING_GET_DATA(str), len);
 
29488
        return len;
 
29489
}
 
29490
 
 
29491
size_t duk_hbuffer_insert_xutf8(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint32_t codepoint) {
 
29492
        duk_uint8_t tmp[DUK_UNICODE_MAX_XUTF8_LENGTH];
 
29493
        size_t len;
 
29494
 
 
29495
        DUK_ASSERT(thr != NULL);
 
29496
        DUK_ASSERT(buf != NULL);
 
29497
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29498
        /* No range assertion for 'codepoint' */
 
29499
 
 
29500
        /* Intentionally no fast path: insertion is not that central */
 
29501
 
 
29502
        /* FIXME: cp -> duk_codepoint_t */
 
29503
        len = (size_t) duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, tmp);
 
29504
        duk_hbuffer_insert_bytes(thr, buf, offset, tmp, len);
 
29505
        return len;
 
29506
}
 
29507
 
 
29508
/* Append a Unicode codepoint to the buffer in CESU-8 format, i.e., convert
 
29509
 * non-BMP characters to surrogate pairs which are then "UTF-8" encoded.
 
29510
 * If the codepoint is initially a surrogate, it is also encoded into CESU-8.
 
29511
 * Codepoints above valid Unicode range (> U+10FFFF) are mangled.
 
29512
 */
 
29513
 
 
29514
size_t duk_hbuffer_insert_cesu8(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, duk_uint32_t codepoint) {
 
29515
        duk_uint8_t tmp[DUK_UNICODE_MAX_CESU8_LENGTH];
 
29516
        size_t len;
 
29517
 
 
29518
        DUK_ASSERT(thr != NULL);
 
29519
        DUK_ASSERT(buf != NULL);
 
29520
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29521
        DUK_ASSERT_DISABLE(codepoint >= 0);
 
29522
        DUK_ASSERT(codepoint <= 0x10ffff);  /* if not in this range, results are garbage (but no crash) */
 
29523
 
 
29524
        /* Intentionally no fast path: insertion is not that central */
 
29525
 
 
29526
        /* FIXME: cp -> duk_codepoint_t */
 
29527
        len = (size_t) duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, tmp);
 
29528
        duk_hbuffer_insert_bytes(thr, buf, offset, tmp, len);
 
29529
        return len;
 
29530
}
 
29531
 
 
29532
/*
 
29533
 *  Appends
 
29534
 *
 
29535
 *  Note: an optimized duk_hbuffer_append_bytes() could be implemented, but
 
29536
 *  it is more compact to use duk_hbuffer_insert_bytes() instead.  The
 
29537
 *  important fast paths bypass these functions. anyway.
 
29538
 */
 
29539
 
 
29540
void duk_hbuffer_append_bytes(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint8_t *data, size_t length) {
 
29541
        DUK_ASSERT(thr != NULL);
 
29542
        DUK_ASSERT(buf != NULL);
 
29543
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29544
        DUK_ASSERT(data != NULL);
 
29545
 
 
29546
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), data, length);
 
29547
}
 
29548
 
 
29549
void duk_hbuffer_append_byte(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint8_t byte) {
 
29550
        DUK_ASSERT(thr != NULL);
 
29551
        DUK_ASSERT(buf != NULL);
 
29552
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29553
 
 
29554
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), &byte, 1);
 
29555
}
 
29556
 
 
29557
size_t duk_hbuffer_append_cstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, const char *str) {
 
29558
        size_t len;
 
29559
 
 
29560
        DUK_ASSERT(thr != NULL);
 
29561
        DUK_ASSERT(buf != NULL);
 
29562
        DUK_ASSERT(str != NULL);
 
29563
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29564
 
 
29565
        len = DUK_STRLEN(str);
 
29566
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), (duk_uint8_t *) str, len);
 
29567
        return len;
 
29568
}
 
29569
 
 
29570
size_t duk_hbuffer_append_hstring(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_hstring *str) {
 
29571
        size_t len;
 
29572
 
 
29573
        DUK_ASSERT(thr != NULL);
 
29574
        DUK_ASSERT(buf != NULL);
 
29575
        DUK_ASSERT(str != NULL);
 
29576
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29577
 
 
29578
        len = DUK_HSTRING_GET_BYTELEN(str);
 
29579
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), (duk_uint8_t *) DUK_HSTRING_GET_DATA(str), len);
 
29580
        return len;
 
29581
}
 
29582
 
 
29583
/* Append a Unicode codepoint to the buffer in extended UTF-8 format, i.e.
 
29584
 * allow codepoints above standard Unicode range (> U+10FFFF) up to seven
 
29585
 * byte encoding (36 bits, but argument type is 32 bits).  In particular,
 
29586
 * allows encoding of all unsigned 32-bit integers.  If the codepoint is
 
29587
 * initially a surrogate, it is encoded without checking (and will become,
 
29588
 * effectively, CESU-8 encoded).
 
29589
 */
 
29590
 
 
29591
size_t duk_hbuffer_append_xutf8(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t codepoint) {
 
29592
        duk_uint8_t tmp[DUK_UNICODE_MAX_XUTF8_LENGTH];
 
29593
        size_t len;
 
29594
 
 
29595
        DUK_ASSERT(thr != NULL);
 
29596
        DUK_ASSERT(buf != NULL);
 
29597
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29598
        /* No range assertion for 'codepoint' */
 
29599
 
 
29600
        if (codepoint < 0x80 && DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) > 0) {
 
29601
                /* fast path: ASCII and there is spare */
 
29602
                duk_uint8_t *p = ((duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf)) + DUK_HBUFFER_GET_SIZE(buf);
 
29603
                *p = (duk_uint8_t) codepoint;
 
29604
                buf->size += 1;
 
29605
                return 1;
 
29606
        }
 
29607
 
 
29608
        /* FIXME: cp -> duk_codepoint_t */
 
29609
        len = (size_t) duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, tmp);
 
29610
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), tmp, len);
 
29611
        return len;
 
29612
}
 
29613
 
 
29614
/* Append a Unicode codepoint to the buffer in CESU-8 format, i.e., convert
 
29615
 * non-BMP characters to surrogate pairs which are then "UTF-8" encoded.
 
29616
 * If the codepoint is initially a surrogate, it is also encoded into CESU-8.
 
29617
 * Codepoints above valid Unicode range (> U+10FFFF) are mangled.
 
29618
 */
 
29619
 
 
29620
size_t duk_hbuffer_append_cesu8(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t codepoint) {
 
29621
        duk_uint8_t tmp[DUK_UNICODE_MAX_CESU8_LENGTH];
 
29622
        size_t len;
 
29623
 
 
29624
        DUK_ASSERT(thr != NULL);
 
29625
        DUK_ASSERT(buf != NULL);
 
29626
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29627
        DUK_ASSERT_DISABLE(codepoint >= 0);
 
29628
        DUK_ASSERT(codepoint <= 0x10ffff);  /* if not in this range, results are garbage (but no crash) */
 
29629
 
 
29630
        if (codepoint < 0x80 && DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) > 0) {
 
29631
                /* fast path: ASCII and there is spare */
 
29632
                duk_uint8_t *p = ((duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf)) + DUK_HBUFFER_GET_SIZE(buf);
 
29633
                *p = (duk_uint8_t) codepoint;
 
29634
                buf->size += 1;
 
29635
                return 1;
 
29636
        }
 
29637
 
 
29638
        /* FIXME: cp -> duk_codepoint_t */
 
29639
        len = (size_t) duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, tmp);
 
29640
        duk_hbuffer_insert_bytes(thr, buf, DUK_HBUFFER_GET_SIZE(buf), tmp, len);
 
29641
        return len;
 
29642
}
 
29643
 
 
29644
/* Append an duk_uint32_t in native byte order.  This is used to emit bytecode
 
29645
 * instructions.
 
29646
 */
 
29647
 
 
29648
void duk_hbuffer_append_native_u32(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_uint32_t val) {
 
29649
        /* relies on duk_uint32_t being exactly right size */
 
29650
        duk_hbuffer_insert_bytes(thr,
 
29651
                                 buf,
 
29652
                                 DUK_HBUFFER_GET_SIZE(buf),
 
29653
                                 (duk_uint8_t *) &val,
 
29654
                                 sizeof(duk_uint32_t));
 
29655
}
 
29656
 
 
29657
/*
 
29658
 *  In-buffer "slices"
 
29659
 *
 
29660
 *  Slices are identified with an offset+length pair, referring to the current
 
29661
 *  buffer data.  A caller cannot otherwise reliably refer to existing data,
 
29662
 *  because the buffer may be reallocated before a data pointer is referenced.
 
29663
 */
 
29664
 
 
29665
void duk_hbuffer_remove_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t offset, size_t length) {
 
29666
        char *p;
 
29667
        size_t end_offset;
 
29668
 
 
29669
        DUK_UNREF(thr);
 
29670
 
 
29671
        DUK_ASSERT(thr != NULL);
 
29672
        DUK_ASSERT(buf != NULL);
 
29673
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29674
        DUK_ASSERT_DISABLE(offset >= 0);                               /* always true */
 
29675
        DUK_ASSERT(offset <= DUK_HBUFFER_GET_SIZE(buf));               /* allow equality */
 
29676
        DUK_ASSERT_DISABLE(length >= 0);                               /* always true */
 
29677
        DUK_ASSERT(offset + length <= DUK_HBUFFER_GET_SIZE(buf));      /* allow equality */
 
29678
 
 
29679
        if (length == 0) {
 
29680
                return;
 
29681
        }
 
29682
 
 
29683
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);
 
29684
 
 
29685
        end_offset = offset + length;
 
29686
 
 
29687
        if (end_offset < DUK_HBUFFER_GET_SIZE(buf)) {
 
29688
                /* not strictly from end of buffer; need to shuffle data */
 
29689
                DUK_MEMMOVE(p + offset,
 
29690
                            p + end_offset,
 
29691
                            DUK_HBUFFER_GET_SIZE(buf) - end_offset);  /* always > 0 */
 
29692
        }
 
29693
 
 
29694
        /* Here we want to zero data even with automatic buffer zeroing
 
29695
         * disabled as we depend on this internally too.
 
29696
         */
 
29697
        DUK_MEMZERO(p + DUK_HBUFFER_GET_SIZE(buf) - length,
 
29698
                    length);  /* always > 0 */
 
29699
 
 
29700
        buf->size -= length;
 
29701
 
 
29702
        /* Note: no shrink check, intentional */
 
29703
}
 
29704
 
 
29705
void duk_hbuffer_insert_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t dst_offset, size_t src_offset, size_t length) {
 
29706
        char *p;
 
29707
        size_t src_end_offset;  /* source end (exclusive) in initial buffer */
 
29708
        size_t len;
 
29709
 
 
29710
        DUK_ASSERT(thr != NULL);
 
29711
        DUK_ASSERT(buf != NULL);
 
29712
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29713
        DUK_ASSERT_DISABLE(dst_offset >= 0);                           /* always true */
 
29714
        DUK_ASSERT(dst_offset <= DUK_HBUFFER_GET_SIZE(buf));           /* allow equality */
 
29715
        DUK_ASSERT_DISABLE(src_offset >= 0);                           /* always true */
 
29716
        DUK_ASSERT(src_offset <= DUK_HBUFFER_GET_SIZE(buf));           /* allow equality */
 
29717
        DUK_ASSERT_DISABLE(length >= 0);                               /* always true */
 
29718
        DUK_ASSERT(src_offset + length <= DUK_HBUFFER_GET_SIZE(buf));  /* allow equality */
 
29719
 
 
29720
        if (length == 0) {
 
29721
                return;
 
29722
        }
 
29723
 
 
29724
        if (DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) < length) {
 
29725
                duk_hbuffer_resize(thr,
 
29726
                                   buf,
 
29727
                                   DUK_HBUFFER_GET_SIZE(buf),
 
29728
                                   duk__add_spare(DUK_HBUFFER_GET_SIZE(buf) + length));
 
29729
        }
 
29730
        DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_SPARE_SIZE(buf) >= length);
 
29731
 
 
29732
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(buf);
 
29733
 
 
29734
        /*
 
29735
         *  src_offset and dst_offset refer to the state of the buffer
 
29736
         *  before any changes are made.  This must be taken into account
 
29737
         *  when moving data around; in particular, the source data may
 
29738
         *  "straddle" the dst_offset, so the insert may need to be handled
 
29739
         *  in two pieces.
 
29740
         */
 
29741
 
 
29742
        src_end_offset = src_offset + length;
 
29743
 
 
29744
        /* create a hole for the insert */
 
29745
        len = DUK_HBUFFER_GET_SIZE(buf) - dst_offset;
 
29746
        if (len > 0) {
 
29747
                DUK_MEMMOVE(p + dst_offset + length,
 
29748
                            p + dst_offset,
 
29749
                            len);
 
29750
        }
 
29751
 
 
29752
        if (src_offset < dst_offset) {
 
29753
                if (src_end_offset <= dst_offset) {
 
29754
                        /* entire source is before 'dst_offset' */
 
29755
                        DUK_MEMCPY(p + dst_offset,
 
29756
                                   p + src_offset,
 
29757
                                   length);
 
29758
                } else {
 
29759
                        /* part of the source is before 'dst_offset'; straddles */
 
29760
                        len = dst_offset - src_offset;
 
29761
                        DUK_ASSERT(len >= 1 && len < length);
 
29762
                        DUK_ASSERT(length - len >= 1);
 
29763
                        DUK_MEMCPY(p + dst_offset,
 
29764
                                   p + src_offset,
 
29765
                                   len);
 
29766
                        DUK_MEMCPY(p + dst_offset + len,
 
29767
                                   p + src_offset + length + len,  /* take above memmove() into account */
 
29768
                                   length - len);
 
29769
                }
 
29770
        } else {
 
29771
                /* entire source is after 'dst_offset' */
 
29772
                DUK_MEMCPY(p + dst_offset,
 
29773
                           p + src_offset + length,  /* take above memmove() into account */
 
29774
                           length);
 
29775
        }
 
29776
 
 
29777
        buf->size += length;
 
29778
}
 
29779
 
 
29780
void duk_hbuffer_append_slice(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t src_offset, size_t length) {
 
29781
        DUK_ASSERT(thr != NULL);
 
29782
        DUK_ASSERT(buf != NULL);
 
29783
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
29784
        DUK_ASSERT_DISABLE(src_offset >= 0);                           /* always true */
 
29785
        DUK_ASSERT(src_offset <= DUK_HBUFFER_GET_SIZE(buf));           /* allow equality */
 
29786
        DUK_ASSERT_DISABLE(length >= 0);                               /* always true */
 
29787
        DUK_ASSERT(src_offset + length <= DUK_HBUFFER_GET_SIZE(buf));  /* allow equality */
 
29788
 
 
29789
        duk_hbuffer_insert_slice(thr,
 
29790
                                 buf,
 
29791
                                 DUK_HBUFFER_GET_SIZE(buf),
 
29792
                                 src_offset,
 
29793
                                 length);
 
29794
}
 
29795
 
 
29796
#line 1 "duk_heap_alloc.c"
 
29797
/*
 
29798
 *  duk_heap allocation and freeing.
 
29799
 */
 
29800
 
 
29801
/* include removed: duk_internal.h */
 
29802
 
 
29803
/* constants for built-in string data depacking */
 
29804
#define DUK__BITPACK_LETTER_LIMIT  26
 
29805
#define DUK__BITPACK_UNDERSCORE    26
 
29806
#define DUK__BITPACK_FF            27
 
29807
#define DUK__BITPACK_SWITCH1       29
 
29808
#define DUK__BITPACK_SWITCH        30
 
29809
#define DUK__BITPACK_SEVENBIT      31
 
29810
 
 
29811
/*
 
29812
 *  Free a heap object.
 
29813
 *
 
29814
 *  Free heap object and its internal (non-heap) pointers.  Assumes that
 
29815
 *  caller has removed the object from heap allocated list or the string
 
29816
 *  intern table, and any weak references (which strings may have) have
 
29817
 *  been already dealt with.
 
29818
 */
 
29819
 
 
29820
static void duk__free_hobject_inner(duk_heap *heap, duk_hobject *h) {
 
29821
        DUK_ASSERT(heap != NULL);
 
29822
        DUK_ASSERT(h != NULL);
 
29823
 
 
29824
        DUK_FREE(heap, h->p);
 
29825
 
 
29826
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
29827
                duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
 
29828
                DUK_UNREF(f);
 
29829
                /* Currently nothing to free; 'data' is a heap object */
 
29830
        } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
29831
                duk_hnativefunction *f = (duk_hnativefunction *) h;
 
29832
                DUK_UNREF(f);
 
29833
                /* Currently nothing to free */
 
29834
        } else if (DUK_HOBJECT_IS_THREAD(h)) {
 
29835
                duk_hthread *t = (duk_hthread *) h;
 
29836
                DUK_FREE(heap, t->valstack);
 
29837
                DUK_FREE(heap, t->callstack);
 
29838
                DUK_FREE(heap, t->catchstack);
 
29839
                /* Don't free h->resumer because it exists in the heap.
 
29840
                 * Callstack entries also contain function pointers which
 
29841
                 * are not freed for the same reason.
 
29842
                 */
 
29843
 
 
29844
                /* XXX: with 'caller' property the callstack would need
 
29845
                 * to be unwound to update the 'caller' properties of
 
29846
                 * functions in the callstack.
 
29847
                 */
 
29848
        }
 
29849
}
 
29850
 
 
29851
static void duk__free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
 
29852
        DUK_ASSERT(heap != NULL);
 
29853
        DUK_ASSERT(h != NULL);
 
29854
 
 
29855
        if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
 
29856
                duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
 
29857
                DUK_DDDPRINT("free dynamic buffer %p", g->curr_alloc);
 
29858
                DUK_FREE(heap, g->curr_alloc);
 
29859
        }
 
29860
}
 
29861
 
 
29862
void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
 
29863
        DUK_ASSERT(heap);
 
29864
        DUK_ASSERT(hdr);
 
29865
 
 
29866
        DUK_DDDPRINT("free heaphdr %p, htype %d", (void *) hdr, (int) DUK_HEAPHDR_GET_TYPE(hdr));
 
29867
 
 
29868
        switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
 
29869
        case DUK_HTYPE_STRING:
 
29870
                /* no inner refs to free */
 
29871
                break;
 
29872
        case DUK_HTYPE_OBJECT:
 
29873
                duk__free_hobject_inner(heap, (duk_hobject *) hdr);
 
29874
                break;
 
29875
        case DUK_HTYPE_BUFFER:
 
29876
                duk__free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
 
29877
                break;
 
29878
        default:
 
29879
                DUK_UNREACHABLE();
 
29880
        }
 
29881
 
 
29882
        DUK_FREE(heap, hdr);
 
29883
}
 
29884
 
 
29885
/*
 
29886
 *  Free the heap.
 
29887
 *
 
29888
 *  Frees heap-related non-heap-tracked allocations such as the
 
29889
 *  string intern table; then frees the heap allocated objects;
 
29890
 *  and finally frees the heap structure itself.  Reference counts
 
29891
 *  and GC markers are ignored (and not updated) in this process,
 
29892
 *  and finalizers won't be called.
 
29893
 *
 
29894
 *  The heap pointer and heap object pointers must not be used
 
29895
 *  after this call.
 
29896
 */
 
29897
 
 
29898
static void duk__free_allocated(duk_heap *heap) {
 
29899
        duk_heaphdr *curr;
 
29900
        duk_heaphdr *next;
 
29901
 
 
29902
        curr = heap->heap_allocated;
 
29903
        while (curr) {
 
29904
                /* We don't log or warn about freeing zero refcount objects
 
29905
                 * because they may happen with finalizer processing.
 
29906
                 */
 
29907
 
 
29908
                DUK_DDDPRINT("FINALFREE (allocated): %!iO", curr);
 
29909
                next = DUK_HEAPHDR_GET_NEXT(curr);
 
29910
                duk_heap_free_heaphdr_raw(heap, curr);
 
29911
                curr = next;
 
29912
        }
 
29913
}
 
29914
 
 
29915
#ifdef DUK_USE_REFERENCE_COUNTING
 
29916
static void duk__free_refzero_list(duk_heap *heap) {
 
29917
        duk_heaphdr *curr;
 
29918
        duk_heaphdr *next;
 
29919
 
 
29920
        curr = heap->refzero_list;
 
29921
        while (curr) {
 
29922
                DUK_DDDPRINT("FINALFREE (refzero_list): %!iO", curr);
 
29923
                next = DUK_HEAPHDR_GET_NEXT(curr);
 
29924
                duk_heap_free_heaphdr_raw(heap, curr);
 
29925
                curr = next;
 
29926
        }
 
29927
}
 
29928
#endif
 
29929
 
 
29930
#ifdef DUK_USE_MARK_AND_SWEEP
 
29931
static void duk__free_markandsweep_finalize_list(duk_heap *heap) {
 
29932
        duk_heaphdr *curr;
 
29933
        duk_heaphdr *next;
 
29934
 
 
29935
        curr = heap->finalize_list;
 
29936
        while (curr) {
 
29937
                DUK_DDDPRINT("FINALFREE (finalize_list): %!iO", curr);
 
29938
                next = DUK_HEAPHDR_GET_NEXT(curr);
 
29939
                duk_heap_free_heaphdr_raw(heap, curr);
 
29940
                curr = next;
 
29941
        }
 
29942
}
 
29943
#endif
 
29944
 
 
29945
static void duk__free_stringtable(duk_heap *heap) {
 
29946
        duk_uint_fast32_t i;
 
29947
 
 
29948
        /* strings are only tracked by stringtable */
 
29949
        if (heap->st) {
 
29950
                for (i = 0; i < heap->st_size; i++) {
 
29951
                        duk_hstring *e = heap->st[i];
 
29952
                        if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
 
29953
                                continue;
 
29954
                        }
 
29955
 
 
29956
                        /* strings have no inner allocations so free directly */
 
29957
                        DUK_DDDPRINT("FINALFREE (string): %!iO", e);
 
29958
                        DUK_FREE(heap, e);
 
29959
#if 0  /* not strictly necessary */
 
29960
                        heap->st[i] = NULL;
 
29961
#endif
 
29962
                }
 
29963
                DUK_FREE(heap, heap->st);
 
29964
#if 0  /* not strictly necessary */
 
29965
                heap->st = NULL;
 
29966
#endif
 
29967
        }
 
29968
}
 
29969
 
 
29970
static void duk__free_run_finalizers(duk_heap *heap) {
 
29971
        duk_heaphdr *curr;
 
29972
#ifdef DUK_USE_DEBUG
 
29973
        duk_size_t count_obj = 0;
 
29974
#endif
 
29975
 
 
29976
        DUK_ASSERT(heap != NULL);
 
29977
        DUK_ASSERT(heap->heap_thread != NULL);
 
29978
#ifdef DUK_USE_REFERENCE_COUNTING
 
29979
        DUK_ASSERT(heap->refzero_list == NULL);  /* refzero not running -> must be empty */
 
29980
#endif
 
29981
#ifdef DUK_USE_MARK_AND_SWEEP
 
29982
        DUK_ASSERT(heap->finalize_list == NULL);  /* mark-and-sweep not running -> must be empty */
 
29983
#endif
 
29984
 
 
29985
        /* FIXME: here again finalizer thread is the heap_thread which needs
 
29986
         * to be coordinated with finalizer thread fixes.
 
29987
         */
 
29988
 
 
29989
        curr = heap->heap_allocated;
 
29990
        while (curr) {
 
29991
                if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
 
29992
                        /* Only objects in heap_allocated may have finalizers. */
 
29993
                        DUK_ASSERT(heap->heap_thread != NULL);
 
29994
                        DUK_ASSERT(curr != NULL);
 
29995
                        duk_hobject_run_finalizer(heap->heap_thread, (duk_hobject *) curr);
 
29996
#ifdef DUK_USE_DEBUG
 
29997
                        count_obj++;
 
29998
#endif
 
29999
                }
 
30000
                curr = DUK_HEAPHDR_GET_NEXT(curr);
 
30001
        }
 
30002
 
 
30003
        /* Note: count includes all objects, not only those with an actual finalizer. */
 
30004
#ifdef DUK_USE_DEBUG
 
30005
        DUK_DPRINT("checked %d objects for finalizers before freeing heap", (int) count_obj);
 
30006
#endif
 
30007
}
 
30008
 
 
30009
void duk_heap_free(duk_heap *heap) {
 
30010
        DUK_DPRINT("free heap: %p", heap);
 
30011
 
 
30012
        /* Execute finalizers before freeing the heap, even for reachable
 
30013
         * objects, and regardless of whether or not mark-and-sweep is
 
30014
         * enabled.  This gives finalizers the chance to free any native
 
30015
         * resources like file handles, allocations made outside Duktape,
 
30016
         * etc.
 
30017
         *
 
30018
         * FIXME: this perhaps requires an execution time limit.
 
30019
         */
 
30020
        DUK_DPRINT("execute finalizers before freeing heap");
 
30021
#ifdef DUK_USE_MARK_AND_SWEEP
 
30022
        /* run mark-and-sweep a few times just in case (unreachable
 
30023
         * object finalizers run already here)
 
30024
         */
 
30025
        duk_heap_mark_and_sweep(heap, 0);
 
30026
        duk_heap_mark_and_sweep(heap, 0);
 
30027
#endif
 
30028
        duk__free_run_finalizers(heap);
 
30029
 
 
30030
        /* Note: heap->heap_thread, heap->curr_thread, heap->heap_object,
 
30031
         * and heap->log_buffer are on the heap allocated list.
 
30032
         */
 
30033
 
 
30034
        DUK_DPRINT("freeing heap objects of heap: %p", heap);
 
30035
        duk__free_allocated(heap);
 
30036
 
 
30037
#ifdef DUK_USE_REFERENCE_COUNTING
 
30038
        DUK_DPRINT("freeing refzero list of heap: %p", heap);
 
30039
        duk__free_refzero_list(heap);
 
30040
#endif
 
30041
 
 
30042
#ifdef DUK_USE_MARK_AND_SWEEP
 
30043
        DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", heap);
 
30044
        duk__free_markandsweep_finalize_list(heap);
 
30045
#endif
 
30046
 
 
30047
        DUK_DPRINT("freeing string table of heap: %p", heap);
 
30048
        duk__free_stringtable(heap);
 
30049
 
 
30050
        DUK_DPRINT("freeing heap structure: %p", heap);
 
30051
        heap->free_func(heap->alloc_udata, heap);
 
30052
}
 
30053
 
 
30054
/*
 
30055
 *  Allocate a heap.
 
30056
 *
 
30057
 *  String table is initialized with built-in strings from genstrings.py.
 
30058
 */
 
30059
 
 
30060
/* intern built-in strings from precooked data (genstrings.py) */
 
30061
static int duk__init_heap_strings(duk_heap *heap) {
 
30062
        duk_bitdecoder_ctx bd_ctx;
 
30063
        duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
 
30064
        int i, j;
 
30065
 
 
30066
        DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
 
30067
        bd->data = (const duk_uint8_t *) duk_strings_data;
 
30068
        bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
 
30069
 
 
30070
        for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
 
30071
                duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
 
30072
                duk_hstring *h;
 
30073
                int len;
 
30074
                int mode;
 
30075
                int t;
 
30076
 
 
30077
                len = duk_bd_decode(bd, 5);
 
30078
                mode = 32;              /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
 
30079
                for (j = 0; j < len; j++) {
 
30080
                        t = duk_bd_decode(bd, 5);
 
30081
                        if (t < DUK__BITPACK_LETTER_LIMIT) {
 
30082
                                t = t + 'A' + mode;
 
30083
                        } else if (t == DUK__BITPACK_UNDERSCORE) {
 
30084
                                t = (int) '_';
 
30085
                        } else if (t == DUK__BITPACK_FF) {
 
30086
                                /* Internal keys are prefixed with 0xFF in the stringtable
 
30087
                                 * (which makes them invalid UTF-8 on purpose).
 
30088
                                 */
 
30089
                                t = (int) 0xff;
 
30090
                        } else if (t == DUK__BITPACK_SWITCH1) {
 
30091
                                t = duk_bd_decode(bd, 5);
 
30092
                                DUK_ASSERT(t >= 0 && t <= 25);
 
30093
                                t = t + 'A' + (mode ^ 32);
 
30094
                        } else if (t == DUK__BITPACK_SWITCH) {
 
30095
                                mode = mode ^ 32;
 
30096
                                t = duk_bd_decode(bd, 5);
 
30097
                                DUK_ASSERT(t >= 0 && t <= 25);
 
30098
                                t = t + 'A' + mode;
 
30099
                        } else if (t == DUK__BITPACK_SEVENBIT) {
 
30100
                                t = duk_bd_decode(bd, 7);
 
30101
                        }
 
30102
                        tmp[j] = (duk_uint8_t) t;
 
30103
                }
 
30104
 
 
30105
                DUK_DDDPRINT("intern built-in string %d", i);
 
30106
                h = duk_heap_string_intern(heap, tmp, len);
 
30107
                if (!h) {
 
30108
                        goto error;
 
30109
                }
 
30110
 
 
30111
                /* special flags */
 
30112
 
 
30113
                if (len > 0 && tmp[0] == 0xff) {
 
30114
                        DUK_HSTRING_SET_INTERNAL(h);
 
30115
                }
 
30116
                if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
 
30117
                        DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
 
30118
                }
 
30119
                if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
 
30120
                        DUK_HSTRING_SET_RESERVED_WORD(h);
 
30121
                        if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
 
30122
                                DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
 
30123
                        }
 
30124
                }
 
30125
 
 
30126
                DUK_DDDPRINT("interned: %!O", h);
 
30127
 
 
30128
                /* The incref macro takes a thread pointer but doesn't use it
 
30129
                 * right now.
 
30130
                 */
 
30131
                DUK_HSTRING_INCREF(_never_referenced_, h);
 
30132
 
 
30133
                heap->strs[i] = h;
 
30134
        }
 
30135
 
 
30136
        return 1;
 
30137
 
 
30138
 error:
 
30139
        return 0;
 
30140
}
 
30141
 
 
30142
static int duk__init_heap_thread(duk_heap *heap) {
 
30143
        duk_hthread *thr;
 
30144
        
 
30145
        DUK_DDPRINT("heap init: alloc heap thread");
 
30146
        thr = duk_hthread_alloc(heap,
 
30147
                                DUK_HOBJECT_FLAG_EXTENSIBLE |
 
30148
                                DUK_HOBJECT_FLAG_THREAD |
 
30149
                                DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
 
30150
        if (!thr) {
 
30151
                DUK_DPRINT("failed to alloc heap_thread");
 
30152
                return 0;
 
30153
        }
 
30154
        thr->state = DUK_HTHREAD_STATE_INACTIVE;
 
30155
        thr->strs = heap->strs;
 
30156
 
 
30157
        heap->heap_thread = thr;
 
30158
        DUK_HTHREAD_INCREF(thr, thr);  /* Note: first argument not really used */
 
30159
 
 
30160
        /* 'thr' is now reachable */
 
30161
 
 
30162
        if (!duk_hthread_init_stacks(heap, thr)) {
 
30163
                return 0;
 
30164
        }
 
30165
 
 
30166
        /* FIXME: this may now fail, and is not handled correctly */
 
30167
        duk_hthread_create_builtin_objects(thr);
 
30168
 
 
30169
        /* default prototype (Note: 'thr' must be reachable) */
 
30170
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
 
30171
 
 
30172
        return 1;
 
30173
}
 
30174
 
 
30175
#ifdef DUK_USE_DEBUG
 
30176
#define DUK__DUMPSZ(t)  do { \
 
30177
                DUK_DPRINT("" #t "=%d", (int) sizeof(t)); \
 
30178
        } while (0)
 
30179
 
 
30180
static void duk__dump_type_sizes(void) {
 
30181
        DUK_DPRINT("sizeofs()");
 
30182
 
 
30183
        /* basic platform types */
 
30184
        DUK__DUMPSZ(char);
 
30185
        DUK__DUMPSZ(short);
 
30186
        DUK__DUMPSZ(int);
 
30187
        DUK__DUMPSZ(long);
 
30188
        DUK__DUMPSZ(double);
 
30189
        DUK__DUMPSZ(void *);
 
30190
        DUK__DUMPSZ(size_t);
 
30191
 
 
30192
        /* basic types from duk_features.h */
 
30193
        DUK__DUMPSZ(uint8_t);
 
30194
        DUK__DUMPSZ(int8_t);
 
30195
        DUK__DUMPSZ(uint16_t);
 
30196
        DUK__DUMPSZ(int16_t);
 
30197
        DUK__DUMPSZ(uint32_t);
 
30198
        DUK__DUMPSZ(int32_t);
 
30199
        DUK__DUMPSZ(uint64_t);
 
30200
        DUK__DUMPSZ(int64_t);
 
30201
        DUK__DUMPSZ(uint_least8_t);
 
30202
        DUK__DUMPSZ(int_least8_t);
 
30203
        DUK__DUMPSZ(uint_least16_t);
 
30204
        DUK__DUMPSZ(int_least16_t);
 
30205
        DUK__DUMPSZ(uint_least32_t);
 
30206
        DUK__DUMPSZ(int_least32_t);
 
30207
        DUK__DUMPSZ(uint_least64_t);
 
30208
        DUK__DUMPSZ(int_least64_t);
 
30209
        DUK__DUMPSZ(uint_fast8_t);
 
30210
        DUK__DUMPSZ(int_fast8_t);
 
30211
        DUK__DUMPSZ(uint_fast16_t);
 
30212
        DUK__DUMPSZ(int_fast16_t);
 
30213
        DUK__DUMPSZ(uint_fast32_t);
 
30214
        DUK__DUMPSZ(int_fast32_t);
 
30215
        DUK__DUMPSZ(uint_fast64_t);
 
30216
        DUK__DUMPSZ(int_fast64_t);
 
30217
        DUK__DUMPSZ(uintptr_t);
 
30218
        DUK__DUMPSZ(intptr_t);
 
30219
        DUK__DUMPSZ(uintmax_t);
 
30220
        DUK__DUMPSZ(intmax_t);
 
30221
        DUK__DUMPSZ(duk_small_int_t);
 
30222
        DUK__DUMPSZ(duk_small_uint_t);
 
30223
        DUK__DUMPSZ(duk_codepoint_t);
 
30224
        DUK__DUMPSZ(duk_ucodepoint_t);
 
30225
        DUK__DUMPSZ(duk_double_t);
 
30226
 
 
30227
        /* tval */
 
30228
        DUK__DUMPSZ(duk_double_union);
 
30229
        DUK__DUMPSZ(duk_tval);
 
30230
 
 
30231
        /* structs from duk_forwdecl.h */
 
30232
        DUK__DUMPSZ(duk_jmpbuf);
 
30233
        DUK__DUMPSZ(duk_heaphdr);
 
30234
        DUK__DUMPSZ(duk_heaphdr_string);
 
30235
        DUK__DUMPSZ(duk_hstring);
 
30236
        DUK__DUMPSZ(duk_hobject);
 
30237
        DUK__DUMPSZ(duk_hcompiledfunction);
 
30238
        DUK__DUMPSZ(duk_hnativefunction);
 
30239
        DUK__DUMPSZ(duk_hthread);
 
30240
        DUK__DUMPSZ(duk_hbuffer);
 
30241
        DUK__DUMPSZ(duk_hbuffer_fixed);
 
30242
        DUK__DUMPSZ(duk_hbuffer_dynamic);
 
30243
        DUK__DUMPSZ(duk_propaccessor);
 
30244
        DUK__DUMPSZ(duk_propvalue);
 
30245
        DUK__DUMPSZ(duk_propdesc);
 
30246
        DUK__DUMPSZ(duk_heap);
 
30247
        DUK__DUMPSZ(duk_activation);
 
30248
        DUK__DUMPSZ(duk_catcher);
 
30249
        DUK__DUMPSZ(duk_strcache);
 
30250
        DUK__DUMPSZ(duk_ljstate);
 
30251
        DUK__DUMPSZ(duk_fixedbuffer);
 
30252
        DUK__DUMPSZ(duk_bitdecoder_ctx);
 
30253
        DUK__DUMPSZ(duk_bitencoder_ctx);
 
30254
        DUK__DUMPSZ(duk_token);
 
30255
        DUK__DUMPSZ(duk_re_token);
 
30256
        DUK__DUMPSZ(duk_lexer_point);
 
30257
        DUK__DUMPSZ(duk_lexer_ctx);
 
30258
        DUK__DUMPSZ(duk_compiler_instr);
 
30259
        DUK__DUMPSZ(duk_compiler_func);
 
30260
        DUK__DUMPSZ(duk_compiler_ctx);
 
30261
        DUK__DUMPSZ(duk_re_matcher_ctx);
 
30262
        DUK__DUMPSZ(duk_re_compiler_ctx);
 
30263
}
 
30264
#undef DUK__DUMPSZ
 
30265
#endif  /* DUK_USE_DEBUG */
 
30266
 
 
30267
duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
 
30268
                         duk_realloc_function realloc_func,
 
30269
                         duk_free_function free_func,
 
30270
                         void *alloc_udata,
 
30271
                         duk_fatal_function fatal_func) {
 
30272
        duk_heap *res = NULL;
 
30273
 
 
30274
        DUK_DPRINT("allocate heap");
 
30275
 
 
30276
        /* Debug dump type sizes */
 
30277
#ifdef DUK_USE_DEBUG
 
30278
        duk__dump_type_sizes();
 
30279
#endif
 
30280
 
 
30281
        /* If selftests enabled, run them as early as possible. */
 
30282
#ifdef DUK_USE_SELF_TESTS
 
30283
        DUK_DPRINT("running self tests");
 
30284
        duk_selftest_run_tests();
 
30285
        DUK_DPRINT("self tests passed");
 
30286
#endif
 
30287
 
 
30288
#ifdef DUK_USE_COMPUTED_NAN
 
30289
        do {
 
30290
                /* Workaround for some exotic platforms where NAN is missing
 
30291
                 * and the expression (0.0 / 0.0) does NOT result in a NaN.
 
30292
                 * Such platforms use the global 'duk_computed_nan' which must
 
30293
                 * be initialized at runtime.  Use 'volatile' to ensure that
 
30294
                 * the compiler will actually do the computation and not try
 
30295
                 * to do constant folding which might result in the original
 
30296
                 * problem.
 
30297
                 */
 
30298
                volatile double dbl1 = 0.0;
 
30299
                volatile double dbl2 = 0.0;
 
30300
                duk_computed_nan = dbl1 / dbl2;
 
30301
        } while (0);
 
30302
#endif
 
30303
 
 
30304
#ifdef DUK_USE_COMPUTED_INFINITY
 
30305
        do {
 
30306
                /* Similar workaround for INFINITY. */
 
30307
                volatile double dbl1 = 1.0;
 
30308
                volatile double dbl2 = 0.0;
 
30309
                duk_computed_infinity = dbl1 / dbl2;
 
30310
        } while (0);
 
30311
#endif
 
30312
 
 
30313
        /* use a raw call, all macros expect the heap to be initialized */
 
30314
        res = (duk_heap *) alloc_func(alloc_udata, sizeof(duk_heap));
 
30315
        if (!res) {
 
30316
                goto error;
 
30317
        }
 
30318
 
 
30319
        /* zero everything */
 
30320
        DUK_MEMZERO(res, sizeof(*res));
 
30321
 
 
30322
        /* explicit NULL inits */
 
30323
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
30324
        res->alloc_udata = NULL;
 
30325
        res->heap_allocated = NULL;
 
30326
#ifdef DUK_USE_REFERENCE_COUNTING
 
30327
        res->refzero_list = NULL;
 
30328
        res->refzero_list_tail = NULL;
 
30329
#endif
 
30330
#ifdef DUK_USE_MARK_AND_SWEEP
 
30331
        res->finalize_list = NULL;
 
30332
#endif
 
30333
        res->heap_thread = NULL;
 
30334
        res->curr_thread = NULL;
 
30335
        res->heap_object = NULL;
 
30336
        res->log_buffer = NULL;
 
30337
        res->st = NULL;
 
30338
        {
 
30339
                int i;
 
30340
                for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
 
30341
                        res->strs[i] = NULL;
 
30342
                }
 
30343
        }
 
30344
#endif
 
30345
 
 
30346
        /* initialize the structure, roughly in order */
 
30347
        res->alloc_func = alloc_func;
 
30348
        res->realloc_func = realloc_func;
 
30349
        res->free_func = free_func;
 
30350
        res->alloc_udata = alloc_udata;
 
30351
        res->fatal_func = fatal_func;
 
30352
 
 
30353
        /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
 
30354
 
 
30355
        res->call_recursion_depth = 0;
 
30356
        res->call_recursion_limit = DUK_HEAP_DEFAULT_CALL_RECURSION_LIMIT;
 
30357
 
 
30358
        /* FIXME: use the pointer as a seed for now: mix in time at least */
 
30359
 
 
30360
        /* cast through C99 intptr_t to avoid GCC warning:
 
30361
         *
 
30362
         *   warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
 
30363
         */
 
30364
        res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
 
30365
        res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
 
30366
 
 
30367
#ifdef DUK_USE_INTERRUPT_COUNTER
 
30368
        /* zero value causes an interrupt before executing first instruction */
 
30369
        DUK_ASSERT(res->interrupt_counter == 0);
 
30370
        DUK_ASSERT(res->interrupt_init == 0);
 
30371
#endif
 
30372
 
 
30373
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
30374
        res->lj.jmpbuf_ptr = NULL;
 
30375
#endif
 
30376
        DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN);  /* zero */
 
30377
 
 
30378
        DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value1);
 
30379
        DUK_TVAL_SET_UNDEFINED_UNUSED(&res->lj.value2);
 
30380
 
 
30381
#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
 
30382
#error initial heap stringtable size is defined incorrectly
 
30383
#endif
 
30384
 
 
30385
        res->st = (duk_hstring **) alloc_func(alloc_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
 
30386
        if (!res->st) {
 
30387
                goto error;
 
30388
        }
 
30389
        res->st_size = DUK_STRTAB_INITIAL_SIZE;
 
30390
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
30391
        {
 
30392
                duk_uint_fast32_t i;
 
30393
                for (i = 0; i < res->st_size; i++) {
 
30394
                        res->st[i] = NULL;
 
30395
                }
 
30396
        }
 
30397
#else
 
30398
        DUK_MEMZERO(res->st, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
 
30399
#endif
 
30400
 
 
30401
        /* strcache init */
 
30402
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
30403
        {
 
30404
                int i;
 
30405
                for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
30406
                        res->strcache[i].h = NULL;
 
30407
                }
 
30408
        }
 
30409
#endif
 
30410
 
 
30411
        /* FIXME: error handling is incomplete.  It would be cleanest if
 
30412
         * there was a setjmp catchpoint, so that all init code could
 
30413
         * freely throw errors.  If that were the case, the return code
 
30414
         * passing here could be removed.
 
30415
         */
 
30416
 
 
30417
        /* built-in strings */
 
30418
        DUK_DDPRINT("HEAP: INIT STRINGS");
 
30419
        if (!duk__init_heap_strings(res)) {
 
30420
                goto error;
 
30421
        }
 
30422
 
 
30423
        /* heap thread */
 
30424
        DUK_DDPRINT("HEAP: INIT HEAP THREAD");
 
30425
        if (!duk__init_heap_thread(res)) {
 
30426
                goto error;
 
30427
        }
 
30428
 
 
30429
        /* heap object */
 
30430
        DUK_DDPRINT("HEAP: INIT HEAP OBJECT");
 
30431
        DUK_ASSERT(res->heap_thread != NULL);
 
30432
        res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
 
30433
                                                  DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
 
30434
        if (!res->heap_object) {
 
30435
                goto error;
 
30436
        }
 
30437
        DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
 
30438
 
 
30439
        /* log buffer */
 
30440
        DUK_DDPRINT("HEAP: INIT LOG BUFFER");
 
30441
        res->log_buffer = (duk_hbuffer_dynamic *) duk_hbuffer_alloc(res,
 
30442
                                                                    DUK_BI_LOGGER_SHORT_MSG_LIMIT,
 
30443
                                                                    1 /*dynamic*/);
 
30444
        if (!res->log_buffer) {
 
30445
                goto error;
 
30446
        }
 
30447
        DUK_HBUFFER_INCREF(res->heap_thread, res->log_buffer);
 
30448
 
 
30449
        DUK_DPRINT("allocated heap: %p", res);
 
30450
        return res;
 
30451
 
 
30452
 error:
 
30453
        DUK_DPRINT("heap allocation failed");
 
30454
 
 
30455
        if (res) {
 
30456
                /* assumes that allocated pointers and alloc funcs are valid
 
30457
                 * if res exists
 
30458
                 */
 
30459
                DUK_ASSERT(res->alloc_func != NULL);
 
30460
                DUK_ASSERT(res->realloc_func != NULL);
 
30461
                DUK_ASSERT(res->free_func != NULL);
 
30462
                duk_heap_free(res);
 
30463
        }
 
30464
        return NULL;
 
30465
}
 
30466
 
 
30467
#line 1 "duk_heap_hashstring.c"
 
30468
/*
 
30469
 *  String hash computation (interning).
 
30470
 */
 
30471
 
 
30472
/* include removed: duk_internal.h */
 
30473
 
 
30474
/* constants for duk_hashstring() */
 
30475
#define DUK__STRHASH_SHORTSTRING   4096
 
30476
#define DUK__STRHASH_MEDIUMSTRING  (256 * 1024)
 
30477
#define DUK__STRHASH_BLOCKSIZE     256
 
30478
 
 
30479
duk_uint32_t duk_heap_hashstring(duk_heap *heap, duk_uint8_t *str, duk_size_t len) {
 
30480
        /*
 
30481
         *  Sampling long strings by byte skipping (like Lua does) is potentially
 
30482
         *  a cache problem.  Here we do 'block skipping' instead for long strings:
 
30483
         *  hash an initial part, and then sample the rest of the string with
 
30484
         *  reasonably sized chunks.
 
30485
         *
 
30486
         *  Skip should depend on length and bound the total time to roughly
 
30487
         *  logarithmic.
 
30488
         *
 
30489
         *  With current values:
 
30490
         *
 
30491
         *    1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
 
30492
         *    1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
 
30493
         *
 
30494
         *  After an initial part has been hashed, an offset is applied before
 
30495
         *  starting the sampling.  The initial offset is computed from the
 
30496
         *  hash of the initial part of the string.  The idea is to avoid the
 
30497
         *  case that all long strings have certain offset ranges that are never
 
30498
         *  sampled.
 
30499
         */
 
30500
        
 
30501
        /* note: mixing len into seed improves hashing when skipping */
 
30502
        duk_uint32_t str_seed = heap->hash_seed ^ len;
 
30503
 
 
30504
        if (len <= DUK__STRHASH_SHORTSTRING) {
 
30505
                return duk_util_hashbytes(str, len, str_seed);
 
30506
        } else {
 
30507
                duk_uint32_t hash;
 
30508
                duk_size_t off;
 
30509
                duk_size_t skip;
 
30510
 
 
30511
                if (len <= DUK__STRHASH_MEDIUMSTRING) {
 
30512
                        skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
 
30513
                } else {
 
30514
                        skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
 
30515
                }
 
30516
 
 
30517
                hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
 
30518
                off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
 
30519
 
 
30520
                /* FIXME: inefficient loop */
 
30521
                while (off < len) {
 
30522
                        duk_size_t left = len - off;
 
30523
                        duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
 
30524
                        hash ^= duk_util_hashbytes(str + off, now, str_seed);
 
30525
                        off += skip;
 
30526
                }
 
30527
 
 
30528
                return hash;
 
30529
        }
 
30530
}
 
30531
 
 
30532
#line 1 "duk_heap_markandsweep.c"
 
30533
/*
 
30534
 *  Mark-and-sweep garbage collection.
 
30535
 */
 
30536
 
 
30537
/* include removed: duk_internal.h */
 
30538
 
 
30539
#ifdef DUK_USE_MARK_AND_SWEEP
 
30540
 
 
30541
static void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
 
30542
static void duk__mark_tval(duk_heap *heap, duk_tval *tv);
 
30543
 
 
30544
/*
 
30545
 *  Misc
 
30546
 */
 
30547
 
 
30548
/* Select a thread for mark-and-sweep use.
 
30549
 *
 
30550
 * FIXME: This needs to change later.
 
30551
 */
 
30552
static duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
 
30553
        if (heap->curr_thread) {
 
30554
                return heap->curr_thread;
 
30555
        }
 
30556
        return heap->heap_thread;  /* may be NULL, too */
 
30557
}
 
30558
 
 
30559
/*
 
30560
 *  Marking functions for heap types: mark children recursively
 
30561
 */
 
30562
 
 
30563
static void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
 
30564
        DUK_UNREF(heap);
 
30565
        DUK_UNREF(h);
 
30566
 
 
30567
        DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h);
 
30568
        DUK_ASSERT(h);
 
30569
 
 
30570
        /* nothing to process */
 
30571
}
 
30572
 
 
30573
static void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
 
30574
        duk_uint_fast32_t i;
 
30575
 
 
30576
        DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h);
 
30577
 
 
30578
        DUK_ASSERT(h);
 
30579
 
 
30580
        /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
 
30581
 
 
30582
        for (i = 0; i < h->e_used; i++) {
 
30583
                duk_hstring *key = DUK_HOBJECT_E_GET_KEY(h, i);
 
30584
                if (!key) {
 
30585
                        continue;
 
30586
                }
 
30587
                duk__mark_heaphdr(heap, (duk_heaphdr *) key);
 
30588
                if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h, i)) {
 
30589
                        duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->a.get);
 
30590
                        duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->a.set);
 
30591
                } else {
 
30592
                        duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->v);
 
30593
                }
 
30594
        }
 
30595
 
 
30596
        for (i = 0; i < h->a_size; i++) {
 
30597
                duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(h, i));
 
30598
        }
 
30599
 
 
30600
        /* hash part is a 'weak reference' and does not contribute */
 
30601
 
 
30602
        duk__mark_heaphdr(heap, (duk_heaphdr *) h->prototype);
 
30603
 
 
30604
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
30605
                duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
 
30606
                duk_tval *tv, *tv_end;
 
30607
                duk_hobject **funcs, **funcs_end;
 
30608
 
 
30609
                /* 'data' is reachable through every compiled function which
 
30610
                 * contains a reference.
 
30611
                 */
 
30612
 
 
30613
                duk__mark_heaphdr(heap, (duk_heaphdr *) f->data);
 
30614
 
 
30615
                tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(f);
 
30616
                tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(f);
 
30617
                while (tv < tv_end) {
 
30618
                        duk__mark_tval(heap, tv);
 
30619
                        tv++;
 
30620
                }
 
30621
 
 
30622
                funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(f);
 
30623
                funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(f);
 
30624
                while (funcs < funcs_end) {
 
30625
                        duk__mark_heaphdr(heap, (duk_heaphdr *) *funcs);
 
30626
                        funcs++;
 
30627
                }
 
30628
        } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
30629
                duk_hnativefunction *f = (duk_hnativefunction *) h;
 
30630
                DUK_UNREF(f);
 
30631
                /* nothing to mark */
 
30632
        } else if (DUK_HOBJECT_IS_THREAD(h)) {
 
30633
                duk_hthread *t = (duk_hthread *) h;
 
30634
                duk_tval *tv;
 
30635
 
 
30636
                tv = t->valstack;
 
30637
                while (tv < t->valstack_end) {
 
30638
                        duk__mark_tval(heap, tv);
 
30639
                        tv++;
 
30640
                }
 
30641
 
 
30642
                for (i = 0; i < t->callstack_top; i++) {
 
30643
                        duk_activation *act = &t->callstack[i];
 
30644
                        duk__mark_heaphdr(heap, (duk_heaphdr *) act->func);
 
30645
                        duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
 
30646
                        duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
 
30647
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
30648
                        duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
 
30649
#endif
 
30650
                }
 
30651
 
 
30652
#if 0  /* nothing now */
 
30653
                for (i = 0; i < t->catchstack_top; i++) {
 
30654
                        duk_catcher *cat = &t->catchstack[i];
 
30655
                }
 
30656
#endif
 
30657
 
 
30658
                duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
 
30659
 
 
30660
                for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
30661
                        duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
 
30662
                }
 
30663
        }
 
30664
}
 
30665
 
 
30666
/* recursion tracking happens here only */
 
30667
static void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
 
30668
        DUK_DDDPRINT("duk__mark_heaphdr %p, type %d",
 
30669
                     (void *) h,
 
30670
                     h ? (int) DUK_HEAPHDR_GET_TYPE(h) : (int) -1);
 
30671
        if (!h) {
 
30672
                return;
 
30673
        }
 
30674
 
 
30675
        if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
 
30676
                DUK_DDDPRINT("already marked reachable, skip");
 
30677
                return;
 
30678
        }
 
30679
        DUK_HEAPHDR_SET_REACHABLE(h);
 
30680
 
 
30681
        if (heap->mark_and_sweep_recursion_depth >= DUK_HEAP_MARK_AND_SWEEP_RECURSION_LIMIT) {
 
30682
                /* log this with a normal debug level because this should be relatively rare */
 
30683
                DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h);
 
30684
                DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
 
30685
                DUK_HEAPHDR_SET_TEMPROOT(h);
 
30686
                return;
 
30687
        }
 
30688
 
 
30689
        heap->mark_and_sweep_recursion_depth++;
 
30690
 
 
30691
        switch (DUK_HEAPHDR_GET_TYPE(h)) {
 
30692
        case DUK_HTYPE_STRING:
 
30693
                duk__mark_hstring(heap, (duk_hstring *) h);
 
30694
                break;
 
30695
        case DUK_HTYPE_OBJECT:
 
30696
                duk__mark_hobject(heap, (duk_hobject *) h);
 
30697
                break;
 
30698
        case DUK_HTYPE_BUFFER:
 
30699
                /* nothing to mark */
 
30700
                break;
 
30701
        default:
 
30702
                DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %d", (void *) h, (int) DUK_HEAPHDR_GET_TYPE(h));
 
30703
                DUK_UNREACHABLE();
 
30704
        }
 
30705
 
 
30706
        heap->mark_and_sweep_recursion_depth--;
 
30707
}
 
30708
 
 
30709
static void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
 
30710
        DUK_DDDPRINT("duk__mark_tval %p", (void *) tv);
 
30711
        if (!tv) {
 
30712
                return;
 
30713
        }
 
30714
        if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
 
30715
                duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv)); 
 
30716
        }
 
30717
}
 
30718
 
 
30719
/*
 
30720
 *  Mark the heap.
 
30721
 */
 
30722
 
 
30723
static void duk__mark_roots_heap(duk_heap *heap) {
 
30724
        int i;
 
30725
 
 
30726
        DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap);
 
30727
 
 
30728
        duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
 
30729
        duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
 
30730
        duk__mark_heaphdr(heap, (duk_heaphdr *) heap->log_buffer);
 
30731
 
 
30732
        for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
 
30733
                duk_hstring *h = heap->strs[i];
 
30734
                duk__mark_heaphdr(heap, (duk_heaphdr *) h);
 
30735
        }
 
30736
 
 
30737
        duk__mark_tval(heap, &heap->lj.value1);
 
30738
        duk__mark_tval(heap, &heap->lj.value2);
 
30739
}
 
30740
 
 
30741
/*
 
30742
 *  Mark refzero_list objects.
 
30743
 *
 
30744
 *  Objects on the refzero_list have no inbound references.  They might have
 
30745
 *  outbound references to objects that we might free, which would invalidate
 
30746
 *  any references held by the refzero objects.  A refzero object might also
 
30747
 *  be rescued by refcount finalization.  Refzero objects are treated as
 
30748
 *  reachability roots to ensure they (or anything they point to) are not
 
30749
 *  freed in mark-and-sweep.
 
30750
 */
 
30751
 
 
30752
#ifdef DUK_USE_REFERENCE_COUNTING
 
30753
static void duk__mark_refzero_list(duk_heap *heap) {
 
30754
        duk_heaphdr *hdr;
 
30755
 
 
30756
        DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap);
 
30757
 
 
30758
        hdr = heap->refzero_list;
 
30759
        while (hdr) {
 
30760
                duk__mark_heaphdr(heap, hdr);
 
30761
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30762
        }
 
30763
}
 
30764
#endif
 
30765
 
 
30766
/*
 
30767
 *  Mark unreachable, finalizable objects.
 
30768
 *
 
30769
 *  Such objects will be moved aside and their finalizers run later.  They have
 
30770
 *  to be treated as reachability roots for their properties etc to remain
 
30771
 *  allocated.  This marking is only done for unreachable values which would
 
30772
 *  be swept later (refzero_list is thus excluded).
 
30773
 *
 
30774
 *  Objects are first marked FINALIZABLE and only then marked as reachability
 
30775
 *  roots; otherwise circular references might be handled inconsistently.
 
30776
 */
 
30777
 
 
30778
static void duk__mark_finalizable(duk_heap *heap) {
 
30779
        duk_hthread *thr;
 
30780
        duk_heaphdr *hdr;
 
30781
        int count_finalizable = 0;
 
30782
 
 
30783
        DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap);
 
30784
 
 
30785
        thr = duk__get_temp_hthread(heap);
 
30786
        DUK_ASSERT(thr != NULL);
 
30787
 
 
30788
        hdr = heap->heap_allocated;
 
30789
        while (hdr) {
 
30790
                if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
 
30791
                    DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
 
30792
                    !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
 
30793
                    duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
 
30794
 
 
30795
                        /* heaphdr:
 
30796
                         *  - is not reachable
 
30797
                         *  - is an object
 
30798
                         *  - is not a finalized object
 
30799
                         *  - has a finalizer
 
30800
                         */
 
30801
 
 
30802
                        DUK_DDPRINT("unreachable heap object will be finalized -> mark as finalizable and treat as a reachability root: %p", hdr);
 
30803
                        DUK_HEAPHDR_SET_FINALIZABLE(hdr);
 
30804
                        count_finalizable ++;
 
30805
                }
 
30806
 
 
30807
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30808
        }
 
30809
 
 
30810
        if (count_finalizable == 0) {
 
30811
                return;
 
30812
        }
 
30813
 
 
30814
        DUK_DDPRINT("marked %d heap objects as finalizable, now mark them reachable", count_finalizable);
 
30815
 
 
30816
        hdr = heap->heap_allocated;
 
30817
        while (hdr) {
 
30818
                if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
 
30819
                        duk__mark_heaphdr(heap, hdr);
 
30820
                }
 
30821
 
 
30822
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30823
        }
 
30824
 
 
30825
        /* Caller will finish the marking process if we hit a recursion limit. */
 
30826
}
 
30827
 
 
30828
/*
 
30829
 *  Fallback marking handler if recursion limit is reached.
 
30830
 *
 
30831
 *  Iterates 'temproots' until recursion limit is no longer hit.  Note
 
30832
 *  that temproots may reside either in heap allocated list or the
 
30833
 *  refzero work list.  This is a slow scan, but guarantees that we
 
30834
 *  finish with a bounded C stack.
 
30835
 *
 
30836
 *  Note that nodes may have been marked as temproots before this
 
30837
 *  scan begun, OR they may have been marked during the scan (as
 
30838
 *  we process nodes recursively also during the scan).  This is
 
30839
 *  intended behavior.
 
30840
 */
 
30841
 
 
30842
#ifdef DUK_USE_DEBUG
 
30843
static void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, int *count) {
 
30844
#else
 
30845
static void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
 
30846
#endif
 
30847
        if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
 
30848
                DUK_DDDPRINT("not a temp root: %p", (void *) hdr);
 
30849
                return;
 
30850
        }
 
30851
 
 
30852
        DUK_DDDPRINT("found a temp root: %p", (void *) hdr);
 
30853
        DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
 
30854
        DUK_HEAPHDR_CLEAR_REACHABLE(hdr);  /* done so that duk__mark_heaphdr() works correctly */
 
30855
        duk__mark_heaphdr(heap, hdr);
 
30856
 
 
30857
#ifdef DUK_USE_DEBUG
 
30858
        (*count)++;
 
30859
#endif
 
30860
}
 
30861
 
 
30862
static void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
 
30863
        duk_heaphdr *hdr;
 
30864
#ifdef DUK_USE_DEBUG
 
30865
        int count;
 
30866
#endif
 
30867
 
 
30868
        DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap);
 
30869
 
 
30870
        while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
 
30871
                DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots");
 
30872
 
 
30873
#ifdef DUK_USE_DEBUG
 
30874
                count = 0;
 
30875
#endif
 
30876
                DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
 
30877
 
 
30878
                hdr = heap->heap_allocated;
 
30879
                while (hdr) {
 
30880
#ifdef DUK_USE_DEBUG
 
30881
                        duk__handle_temproot(heap, hdr, &count);
 
30882
#else
 
30883
                        duk__handle_temproot(heap, hdr);
 
30884
#endif
 
30885
                        hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30886
                }
 
30887
 
 
30888
                /* must also check refzero_list */
 
30889
#ifdef DUK_USE_REFERENCE_COUNTING
 
30890
                hdr = heap->refzero_list;
 
30891
                while (hdr) {
 
30892
#ifdef DUK_USE_DEBUG
 
30893
                        duk__handle_temproot(heap, hdr, &count);
 
30894
#else
 
30895
                        duk__handle_temproot(heap, hdr);
 
30896
#endif
 
30897
                        hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30898
                }
 
30899
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
30900
 
 
30901
#ifdef DUK_USE_DEBUG
 
30902
                DUK_DDPRINT("temproot mark heap scan processed %d temp roots", count);
 
30903
#endif
 
30904
        }
 
30905
}
 
30906
 
 
30907
/*
 
30908
 *  Finalize refcounts for heap elements just about to be freed.
 
30909
 *  This must be done for all objects before freeing to avoid any
 
30910
 *  stale pointer dereferences.
 
30911
 *
 
30912
 *  Note that this must deduce the set of objects to be freed
 
30913
 *  identically to duk__sweep_heap().
 
30914
 */
 
30915
 
 
30916
#ifdef DUK_USE_REFERENCE_COUNTING
 
30917
static void duk__finalize_refcounts(duk_heap *heap) {
 
30918
        duk_hthread *thr;
 
30919
        duk_heaphdr *hdr;
 
30920
 
 
30921
        thr = duk__get_temp_hthread(heap);
 
30922
        DUK_ASSERT(thr != NULL);
 
30923
 
 
30924
        DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
 
30925
                    (void *) heap, (void *) thr);
 
30926
 
 
30927
        hdr = heap->heap_allocated;
 
30928
        while (hdr) {
 
30929
                if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
 
30930
                        /*
 
30931
                         *  Unreachable object about to be swept.  Finalize target refcounts
 
30932
                         *  (objects which the unreachable object points to) without doing
 
30933
                         *  refzero processing.  Recursive decrefs are also prevented when
 
30934
                         *  refzero processing is disabled.
 
30935
                         *
 
30936
                         *  Value cannot be a finalizable object, as they have been made
 
30937
                         *  temporarily reachable for this round.
 
30938
                         */
 
30939
 
 
30940
                        DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr);
 
30941
                        duk_heap_refcount_finalize_heaphdr(thr, hdr);
 
30942
                }
 
30943
 
 
30944
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30945
        }
 
30946
}
 
30947
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
30948
 
 
30949
/*
 
30950
 *  Clear (reachable) flags of refzero work list.
 
30951
 */
 
30952
 
 
30953
#ifdef DUK_USE_REFERENCE_COUNTING
 
30954
static void duk__clear_refzero_list_flags(duk_heap *heap) {
 
30955
        duk_heaphdr *hdr;
 
30956
 
 
30957
        DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap);
 
30958
 
 
30959
        hdr = heap->refzero_list;
 
30960
        while (hdr) {
 
30961
                DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
 
30962
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
 
30963
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
 
30964
                DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
 
30965
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
30966
        }
 
30967
}
 
30968
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
30969
 
 
30970
/*
 
30971
 *  Sweep stringtable
 
30972
 */
 
30973
 
 
30974
static void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) {
 
30975
        duk_hstring *h;
 
30976
        duk_uint_fast32_t i;
 
30977
#ifdef DUK_USE_DEBUG
 
30978
        duk_size_t count_free = 0;
 
30979
#endif
 
30980
        duk_size_t count_keep = 0;
 
30981
 
 
30982
        DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap);
 
30983
 
 
30984
        for (i = 0; i < heap->st_size; i++) {
 
30985
                h = heap->st[i];
 
30986
                if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
 
30987
                        continue;
 
30988
                } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
 
30989
                        DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
 
30990
                        count_keep++;
 
30991
                        continue;
 
30992
                }
 
30993
 
 
30994
#ifdef DUK_USE_DEBUG
 
30995
                count_free++;
 
30996
#endif
 
30997
 
 
30998
#if defined(DUK_USE_DEBUG) && defined(DUK_USE_REFERENCE_COUNTING)
 
30999
                /* Non-zero refcounts should not happen for unreachable strings,
 
31000
                 * because we refcount finalize all unreachable objects which
 
31001
                 * should have decreased unreachable string refcounts to zero
 
31002
                 * (even for cycles).
 
31003
                 */
 
31004
                DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
 
31005
#endif
 
31006
 
 
31007
                DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h);
 
31008
 
 
31009
                /* deal with weak references first */
 
31010
                duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
 
31011
 
 
31012
                /* remove the string (mark DELETED), could also call
 
31013
                 * duk_heap_string_remove() but that would be slow and
 
31014
                 * pointless because we already know the slot.
 
31015
                 */
 
31016
                heap->st[i] = DUK_STRTAB_DELETED_MARKER(heap);
 
31017
 
 
31018
                /* then free */
 
31019
#if 1
 
31020
                DUK_FREE(heap, (duk_heaphdr *) h);  /* no inner refs/allocs, just free directly */
 
31021
#else
 
31022
                duk_heap_free_heaphdr_raw(heap, (duk_heaphdr *) h);  /* this would be OK but unnecessary */
 
31023
#endif
 
31024
        }
 
31025
 
 
31026
#ifdef DUK_USE_DEBUG
 
31027
        DUK_DPRINT("mark-and-sweep sweep stringtable: %d freed, %d kept",
 
31028
                   (int) count_free, (int) count_keep);
 
31029
#endif
 
31030
        *out_count_keep = count_keep;
 
31031
}
 
31032
 
 
31033
/*
 
31034
 *  Sweep heap
 
31035
 */
 
31036
 
 
31037
static void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
 
31038
        duk_heaphdr *prev;  /* last element that was left in the heap */
 
31039
        duk_heaphdr *curr;
 
31040
        duk_heaphdr *next;
 
31041
#ifdef DUK_USE_DEBUG
 
31042
        duk_size_t count_free = 0;
 
31043
        duk_size_t count_finalize = 0;
 
31044
        duk_size_t count_rescue = 0;
 
31045
#endif
 
31046
        duk_size_t count_keep = 0;
 
31047
 
 
31048
        DUK_UNREF(flags);
 
31049
        DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap);
 
31050
 
 
31051
        prev = NULL;
 
31052
        curr = heap->heap_allocated;
 
31053
        heap->heap_allocated = NULL;
 
31054
        while (curr) {
 
31055
                /* strings are never placed on the heap allocated list */
 
31056
                DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
 
31057
 
 
31058
                next = DUK_HEAPHDR_GET_NEXT(curr);
 
31059
 
 
31060
                if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
 
31061
                        /*
 
31062
                         *  Reachable object, keep
 
31063
                         */
 
31064
 
 
31065
                        DUK_DDDPRINT("sweep, reachable: %p", (void *) curr);
 
31066
 
 
31067
                        if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
 
31068
                                /*
 
31069
                                 *  If object has been marked finalizable, move it to the
 
31070
                                 *  "to be finalized" work list.  It will be collected on
 
31071
                                 *  the next mark-and-sweep if it is still unreachable
 
31072
                                 *  after running the finalizer.
 
31073
                                 */
 
31074
 
 
31075
                                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
 
31076
                                DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
 
31077
                                DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr);
 
31078
 
 
31079
#ifdef DUK_USE_DOUBLE_LINKED_HEAP
 
31080
                                if (heap->finalize_list) {
 
31081
                                        DUK_HEAPHDR_SET_PREV(heap->finalize_list, curr);
 
31082
                                }
 
31083
                                DUK_HEAPHDR_SET_PREV(curr, NULL);
 
31084
#endif
 
31085
                                DUK_HEAPHDR_SET_NEXT(curr, heap->finalize_list);
 
31086
                                heap->finalize_list = curr;
 
31087
#ifdef DUK_USE_DEBUG
 
31088
                                count_finalize++;
 
31089
#endif
 
31090
                        } else {
 
31091
                                /*
 
31092
                                 *  Object will be kept; queue object back to heap_allocated (to tail)
 
31093
                                 */
 
31094
 
 
31095
                                if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
 
31096
                                        /*
 
31097
                                         *  Object's finalizer was executed on last round, and
 
31098
                                         *  object has been happily rescued.
 
31099
                                         */
 
31100
 
 
31101
                                        DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
 
31102
                                        DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
 
31103
                                        DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr);
 
31104
#ifdef DUK_USE_DEBUG
 
31105
                                        count_rescue++;
 
31106
#endif
 
31107
                                } else {
 
31108
                                        /*
 
31109
                                         *  Plain, boring reachable object.
 
31110
                                         */
 
31111
                                        count_keep++;
 
31112
                                }
 
31113
 
 
31114
                                if (!heap->heap_allocated) {
 
31115
                                        heap->heap_allocated = curr;
 
31116
                                }
 
31117
                                if (prev) {
 
31118
                                        DUK_HEAPHDR_SET_NEXT(prev, curr);
 
31119
                                }
 
31120
#ifdef DUK_USE_DOUBLE_LINKED_HEAP
 
31121
                                DUK_HEAPHDR_SET_PREV(curr, prev);
 
31122
#endif
 
31123
                                prev = curr;
 
31124
                        }
 
31125
 
 
31126
                        DUK_HEAPHDR_CLEAR_REACHABLE(curr);
 
31127
                        DUK_HEAPHDR_CLEAR_FINALIZED(curr);
 
31128
                        DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
 
31129
 
 
31130
                        DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
 
31131
                        DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
 
31132
                        DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
 
31133
 
 
31134
                        curr = next;
 
31135
                } else {
 
31136
                        /*
 
31137
                         *  Unreachable object, free
 
31138
                         */
 
31139
 
 
31140
                        DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr);
 
31141
 
 
31142
#if defined(DUK_USE_DEBUG) && defined(DUK_USE_REFERENCE_COUNTING)
 
31143
                        /* Non-zero refcounts should not happen because we refcount
 
31144
                         * finalize all unreachable objects which should cancel out
 
31145
                         * refcounts (even for cycles).
 
31146
                         */
 
31147
                        DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
 
31148
#endif
 
31149
                        DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
 
31150
 
 
31151
                        if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
 
31152
                                DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr);
 
31153
                        }
 
31154
 
 
31155
                        /* Note: object cannot be a finalizable unreachable object, as
 
31156
                         * they have been marked temporarily reachable for this round,
 
31157
                         * and are handled above.
 
31158
                         */
 
31159
 
 
31160
#ifdef DUK_USE_DEBUG
 
31161
                        count_free++;
 
31162
#endif
 
31163
 
 
31164
                        /* weak refs should be handled here, but no weak refs for
 
31165
                         * any non-string objects exist right now.
 
31166
                         */
 
31167
 
 
31168
                        /* free object and all auxiliary (non-heap) allocs */
 
31169
                        duk_heap_free_heaphdr_raw(heap, curr);
 
31170
 
 
31171
                        curr = next;
 
31172
                }
 
31173
        }
 
31174
        if (prev) {
 
31175
                DUK_HEAPHDR_SET_NEXT(prev, NULL);
 
31176
        }
 
31177
 
 
31178
#ifdef DUK_USE_DEBUG
 
31179
        DUK_DPRINT("mark-and-sweep sweep objects (non-string): %d freed, %d kept, %d rescued, %d queued for finalization",
 
31180
                    (int) count_free, (int) count_keep, (int) count_rescue, (int) count_finalize);
 
31181
#endif
 
31182
        *out_count_keep = count_keep;
 
31183
}
 
31184
 
 
31185
/*
 
31186
 *  Run (object) finalizers in the "to be finalized" work list.
 
31187
 */
 
31188
 
 
31189
static void duk__run_object_finalizers(duk_heap *heap) {
 
31190
        duk_heaphdr *curr;
 
31191
        duk_heaphdr *next;
 
31192
#ifdef DUK_USE_DEBUG
 
31193
        int count = 0;
 
31194
#endif
 
31195
        duk_hthread *thr;
 
31196
 
 
31197
        DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap);
 
31198
 
 
31199
        thr = duk__get_temp_hthread(heap);
 
31200
        DUK_ASSERT(thr != NULL);
 
31201
 
 
31202
        curr = heap->finalize_list;
 
31203
        while (curr) {
 
31204
                DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr);
 
31205
 
 
31206
                DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* only objects have finalizers */
 
31207
                DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));                /* flags have been already cleared */
 
31208
                DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
 
31209
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
 
31210
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
 
31211
 
 
31212
                /* run the finalizer */
 
31213
                duk_hobject_run_finalizer(thr, (duk_hobject *) curr);  /* must never longjmp */
 
31214
 
 
31215
                /* mark FINALIZED, for next mark-and-sweep (will collect unless has become reachable;
 
31216
                 * prevent running finalizer again if reachable)
 
31217
                 */
 
31218
                DUK_HEAPHDR_SET_FINALIZED(curr);
 
31219
 
 
31220
                /* queue back to heap_allocated */
 
31221
                next = DUK_HEAPHDR_GET_NEXT(curr);
 
31222
                DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
 
31223
 
 
31224
                curr = next;
 
31225
#ifdef DUK_USE_DEBUG
 
31226
                count++;
 
31227
#endif
 
31228
        }
 
31229
 
 
31230
        /* finalize_list will always be processed completely */
 
31231
        heap->finalize_list = NULL;
 
31232
 
 
31233
#ifdef DUK_USE_DEBUG
 
31234
        DUK_DPRINT("mark-and-sweep finalize objects: %d finalizers called", count);
 
31235
#endif
 
31236
}
 
31237
 
 
31238
/*
 
31239
 *  Object compaction.
 
31240
 *
 
31241
 *  Compaction is assumed to never throw an error.
 
31242
 */
 
31243
 
 
31244
static int duk__protected_compact_object(duk_context *ctx) {
 
31245
        /* XXX: for threads, compact value stack, call stack, catch stack? */
 
31246
 
 
31247
        duk_hobject *obj = duk_get_hobject(ctx, -1);
 
31248
        DUK_ASSERT(obj != NULL);
 
31249
        duk_hobject_compact_props((duk_hthread *) ctx, obj);
 
31250
        return 0;
 
31251
}
 
31252
 
 
31253
#ifdef DUK_USE_DEBUG
 
31254
static void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, int *p_count_check, int *p_count_compact, int *p_count_bytes_saved) {
 
31255
#else
 
31256
static void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
 
31257
#endif
 
31258
        duk_heaphdr *curr;
 
31259
#ifdef DUK_USE_DEBUG
 
31260
        size_t old_size, new_size;
 
31261
#endif
 
31262
        duk_hobject *obj;
 
31263
 
 
31264
        DUK_UNREF(heap);
 
31265
 
 
31266
        curr = start;
 
31267
        while (curr) {
 
31268
                DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr);
 
31269
 
 
31270
                if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
 
31271
                        goto next;      
 
31272
                }
 
31273
                obj = (duk_hobject *) curr;
 
31274
 
 
31275
#ifdef DUK_USE_DEBUG
 
31276
                old_size = DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size);
 
31277
#endif
 
31278
 
 
31279
                DUK_DDPRINT("compact object: %p", (void *) obj);
 
31280
                duk_push_hobject((duk_context *) thr, obj);
 
31281
                /* XXX: disable error handlers for duration of compaction? */
 
31282
                duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0);
 
31283
 
 
31284
#ifdef DUK_USE_DEBUG
 
31285
                new_size = DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size);
 
31286
#endif
 
31287
 
 
31288
#ifdef DUK_USE_DEBUG
 
31289
                (*p_count_compact)++;
 
31290
                (*p_count_bytes_saved) += old_size - new_size;
 
31291
#endif
 
31292
 
 
31293
         next:
 
31294
                curr = DUK_HEAPHDR_GET_NEXT(curr);
 
31295
#ifdef DUK_USE_DEBUG
 
31296
                (*p_count_check)++;
 
31297
#endif
 
31298
        }
 
31299
}
 
31300
 
 
31301
static void duk__compact_objects(duk_heap *heap) {
 
31302
        /* XXX: which lists should participate?  to be finalized? */
 
31303
#ifdef DUK_USE_DEBUG
 
31304
        int count_check = 0;
 
31305
        int count_compact = 0;
 
31306
        int count_bytes_saved = 0;
 
31307
#endif
 
31308
        duk_hthread *thr;
 
31309
 
 
31310
        DUK_DDPRINT("duk__compact_objects: %p", (void *) heap);
 
31311
 
 
31312
        thr = duk__get_temp_hthread(heap);
 
31313
        DUK_ASSERT(thr != NULL);
 
31314
 
 
31315
#ifdef DUK_USE_DEBUG
 
31316
        duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
 
31317
        duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
 
31318
#ifdef DUK_USE_REFERENCE_COUNTING
 
31319
        duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
 
31320
#endif
 
31321
#else
 
31322
        duk__compact_object_list(heap, thr, heap->heap_allocated);
 
31323
        duk__compact_object_list(heap, thr, heap->finalize_list);
 
31324
#ifdef DUK_USE_REFERENCE_COUNTING
 
31325
        duk__compact_object_list(heap, thr, heap->refzero_list);
 
31326
#endif
 
31327
#endif
 
31328
 
 
31329
#ifdef DUK_USE_DEBUG
 
31330
        DUK_DPRINT("mark-and-sweep compact objects: %d checked, %d compaction attempts, %d bytes saved by compaction", count_check, count_compact, count_bytes_saved);
 
31331
#endif
 
31332
}
 
31333
 
 
31334
/*
 
31335
 *  Assertion helpers.
 
31336
 */
 
31337
 
 
31338
#ifdef DUK_USE_ASSERTIONS
 
31339
static void duk__assert_heaphdr_flags(duk_heap *heap) {
 
31340
        duk_heaphdr *hdr;
 
31341
 
 
31342
        hdr = heap->heap_allocated;
 
31343
        while (hdr) {
 
31344
                DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
 
31345
                DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
 
31346
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
 
31347
                /* may have FINALIZED */
 
31348
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
31349
        }
 
31350
 
 
31351
#ifdef DUK_USE_REFERENCE_COUNTING
 
31352
        hdr = heap->refzero_list;
 
31353
        while (hdr) {
 
31354
                DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
 
31355
                DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
 
31356
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
 
31357
                DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
 
31358
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
31359
        }
 
31360
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
31361
}
 
31362
 
 
31363
#ifdef DUK_USE_REFERENCE_COUNTING
 
31364
static void duk__assert_valid_refcounts(duk_heap *heap) {
 
31365
        duk_heaphdr *hdr = heap->heap_allocated;
 
31366
        while (hdr) {
 
31367
                if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
 
31368
                    DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
 
31369
                        /* An object may be in heap_allocated list with a zero
 
31370
                         * refcount if it has just been finalized and is waiting
 
31371
                         * to be collected by the next cycle.
 
31372
                         */
 
31373
                } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
 
31374
                        /* An object may be in heap_allocated list with a zero
 
31375
                         * refcount also if it is a temporary object created by
 
31376
                         * a finalizer; because finalization now runs inside
 
31377
                         * mark-and-sweep, such objects will not be queued to
 
31378
                         * refzero_list and will thus appear here with refcount
 
31379
                         * zero.
 
31380
                         */
 
31381
#if 0  /* this case can no longer occur because refcount is unsigned */
 
31382
                } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
 
31383
                        DUK_DPRINT("invalid refcount: %d, %p -> %!O",
 
31384
                                   (hdr != NULL ? DUK_HEAPHDR_GET_REFCOUNT(hdr) : 0), (void *) hdr, hdr);
 
31385
                        DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
 
31386
#endif
 
31387
                }
 
31388
                hdr = DUK_HEAPHDR_GET_NEXT(hdr);
 
31389
        }
 
31390
}
 
31391
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
31392
#endif  /* DUK_USE_ASSERTIONS */
 
31393
 
 
31394
/*
 
31395
 *  Main mark-and-sweep function.
 
31396
 *
 
31397
 *  'flags' represents the features requested by the caller.  The current
 
31398
 *  heap->mark_and_sweep_base_flags is ORed automatically into the flags;
 
31399
 *  the base flags mask typically prevents certain mark-and-sweep operations
 
31400
 *  to avoid trouble.
 
31401
 */
 
31402
 
 
31403
int duk_heap_mark_and_sweep(duk_heap *heap, int flags) {
 
31404
        duk_size_t count_keep_obj;
 
31405
        duk_size_t count_keep_str;
 
31406
        duk_size_t tmp;
 
31407
 
 
31408
        /* FIXME: thread selection for mark-and-sweep is currently a hack.
 
31409
         * If we don't have a thread, the entire mark-and-sweep is now
 
31410
         * skipped (although we could just skip finalizations).
 
31411
         */
 
31412
        if (duk__get_temp_hthread(heap) == NULL) {
 
31413
                DUK_DPRINT("temporary hack: gc skipped because we don't have a temp thread");
 
31414
 
 
31415
                /* reset voluntary gc trigger count */
 
31416
#ifdef DUK_USE_VOLUNTARY_GC
 
31417
                heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
 
31418
#endif
 
31419
                return 0;  /* OK */
 
31420
        }
 
31421
 
 
31422
        DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08x, effective flags: 0x%08x",
 
31423
                   flags, flags | heap->mark_and_sweep_base_flags);
 
31424
 
 
31425
        flags |= heap->mark_and_sweep_base_flags;
 
31426
 
 
31427
        /*
 
31428
         *  Assertions before
 
31429
         */
 
31430
 
 
31431
#ifdef DUK_USE_ASSERTIONS
 
31432
        DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
 
31433
        DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
 
31434
        DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
 
31435
        duk__assert_heaphdr_flags(heap);
 
31436
#ifdef DUK_USE_REFERENCE_COUNTING
 
31437
        /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
 
31438
         * finalizer may trigger a mark-and-sweep.
 
31439
         */
 
31440
        duk__assert_valid_refcounts(heap);
 
31441
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
31442
#endif  /* DUK_USE_ASSERTIONS */
 
31443
 
 
31444
        /*
 
31445
         *  Begin
 
31446
         */
 
31447
 
 
31448
        DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
 
31449
 
 
31450
        /*
 
31451
         *  Mark roots, hoping that recursion limit is not normally hit.
 
31452
         *  If recursion limit is hit, run additional reachability rounds
 
31453
         *  starting from "temproots" until marking is complete.
 
31454
         *
 
31455
         *  Marking happens in two phases: first we mark actual reachability
 
31456
         *  roots (and run "temproots" to complete the process).  Then we
 
31457
         *  check which objects are unreachable and are finalizable; such
 
31458
         *  objects are marked as FINALIZABLE and marked as reachability
 
31459
         *  (and "temproots" is run again to complete the process).
 
31460
         */
 
31461
 
 
31462
        duk__mark_roots_heap(heap);               /* main reachability roots */
 
31463
#ifdef DUK_USE_REFERENCE_COUNTING
 
31464
        duk__mark_refzero_list(heap);             /* refzero_list treated as reachability roots */
 
31465
#endif
 
31466
        duk__mark_temproots_by_heap_scan(heap);   /* temproots */
 
31467
 
 
31468
        duk__mark_finalizable(heap);              /* mark finalizable as reachability roots */
 
31469
        duk__mark_temproots_by_heap_scan(heap);   /* temproots */
 
31470
 
 
31471
        /*
 
31472
         *  Sweep garbage and remove marking flags, and move objects with
 
31473
         *  finalizers to the finalizer work list.
 
31474
         *
 
31475
         *  Objects to be swept need to get their refcounts finalized before
 
31476
         *  they are swept.  In other words, their target object refcounts
 
31477
         *  need to be decreased.  This has to be done before freeing any
 
31478
         *  objects to avoid decref'ing dangling pointers (which may happen
 
31479
         *  even without bugs, e.g. with reference loops)
 
31480
         *
 
31481
         *  Because strings don't point to other heap objects, similar
 
31482
         *  finalization is not necessary for strings.
 
31483
         */
 
31484
 
 
31485
        /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
 
31486
 
 
31487
#ifdef DUK_USE_REFERENCE_COUNTING
 
31488
        duk__finalize_refcounts(heap);
 
31489
#endif
 
31490
        duk__sweep_heap(heap, flags, &count_keep_obj);
 
31491
        duk__sweep_stringtable(heap, &count_keep_str);
 
31492
#ifdef DUK_USE_REFERENCE_COUNTING
 
31493
        duk__clear_refzero_list_flags(heap);
 
31494
#endif
 
31495
 
 
31496
        /*
 
31497
         *  Object compaction (emergency only).
 
31498
         *
 
31499
         *  Object compaction is a separate step after sweeping, as there is
 
31500
         *  more free memory for it to work with.  Also, currently compaction
 
31501
         *  may insert new objects into the heap allocated list and the string
 
31502
         *  table which we don't want to do during a sweep (the reachability
 
31503
         *  flags of such objects would be incorrect).  The objects inserted
 
31504
         *  are currently:
 
31505
         *
 
31506
         *    - a temporary duk_hbuffer for a new properties allocation
 
31507
         *    - if array part is abandoned, string keys are interned
 
31508
         *
 
31509
         *  The object insertions go to the front of the list, so they do not
 
31510
         *  cause an infinite loop (they are not compacted).
 
31511
         */
 
31512
 
 
31513
        if ((flags & DUK_MS_FLAG_EMERGENCY) &&
 
31514
            !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
 
31515
                duk__compact_objects(heap);
 
31516
        }
 
31517
 
 
31518
        /*
 
31519
         *  String table resize check.
 
31520
         *
 
31521
         *  Note: this may silently (and safely) fail if GC is caused by an
 
31522
         *  allocation call in stringtable resize_hash().  Resize_hash()
 
31523
         *  will prevent a recursive call to itself by setting the
 
31524
         *  DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
 
31525
         */
 
31526
 
 
31527
        /* XXX: stringtable emergency compaction? */
 
31528
 
 
31529
#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
 
31530
        if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
 
31531
                DUK_DDPRINT("resize stringtable: %p", (void *) heap);
 
31532
                duk_heap_force_stringtable_resize(heap);
 
31533
        } else {
 
31534
                DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set");
 
31535
        }
 
31536
#endif
 
31537
 
 
31538
        /*
 
31539
         *  Finalize objects in the finalization work list.  Finalized
 
31540
         *  objects are queued back to heap_allocated with FINALIZED set.
 
31541
         *
 
31542
         *  Since finalizers may cause arbitrary side effects, they are
 
31543
         *  prevented during string table and object property allocation
 
31544
         *  resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
 
31545
         *  heap->mark_and_sweep_base_flags.  In this case the objects
 
31546
         *  remain in the finalization work list after mark-and-sweep
 
31547
         *  exits and they may be finalized on the next pass.
 
31548
         *
 
31549
         *  Finalization currently happens inside "MARKANDSWEEP_RUNNING"
 
31550
         *  protection (no mark-and-sweep may be triggered by the
 
31551
         *  finalizers).  As a side effect:
 
31552
         *
 
31553
         *    1) an out-of-memory error inside a finalizer will not
 
31554
         *       cause a mark-and-sweep and may cause the finalizer
 
31555
         *       to fail unnecessarily
 
31556
         *
 
31557
         *    2) any temporary objects whose refcount decreases to zero
 
31558
         *       during finalization will not be put into refzero_list;
 
31559
         *       they can only be collected by another mark-and-sweep
 
31560
         *
 
31561
         *  This is not optimal, but since the sweep for this phase has
 
31562
         *  already happened, this is probably good enough for now.
 
31563
         */
 
31564
 
 
31565
        if (!(flags & DUK_MS_FLAG_NO_FINALIZERS)) {
 
31566
                duk__run_object_finalizers(heap);
 
31567
        } else {
 
31568
                DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set");
 
31569
        }
 
31570
 
 
31571
        /*
 
31572
         *  Finish
 
31573
         */
 
31574
 
 
31575
        DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
 
31576
 
 
31577
        /*
 
31578
         *  Assertions after
 
31579
         */
 
31580
 
 
31581
#ifdef DUK_USE_ASSERTIONS
 
31582
        DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
 
31583
        DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
 
31584
        DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
 
31585
        duk__assert_heaphdr_flags(heap);
 
31586
#ifdef DUK_USE_REFERENCE_COUNTING
 
31587
        /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
 
31588
         * finalizer may trigger a mark-and-sweep.
 
31589
         */
 
31590
        duk__assert_valid_refcounts(heap);
 
31591
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
31592
#endif  /* DUK_USE_ASSERTIONS */
 
31593
 
 
31594
        /*
 
31595
         *  Reset trigger counter
 
31596
         */
 
31597
 
 
31598
#ifdef DUK_USE_VOLUNTARY_GC
 
31599
        tmp = (count_keep_obj + count_keep_str) / 256;
 
31600
        heap->mark_and_sweep_trigger_counter =
 
31601
            (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
 
31602
            DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD;
 
31603
        DUK_DPRINT("garbage collect (mark-and-sweep) finished: %d objects kept, %d strings kept, trigger reset to %d",
 
31604
                   (int) count_keep_obj, (int) count_keep_str, (int) heap->mark_and_sweep_trigger_counter);
 
31605
#else
 
31606
        DUK_DPRINT("garbage collect (mark-and-sweep) finished: %d objects kept, %d strings kept, no voluntary trigger",
 
31607
                   (int) count_keep_obj, (int) count_keep_str);
 
31608
#endif
 
31609
        return 0;  /* OK */
 
31610
}
 
31611
 
 
31612
#else  /* DUK_USE_MARK_AND_SWEEP */
 
31613
 
 
31614
/* no mark-and-sweep gc */
 
31615
 
 
31616
#endif  /* DUK_USE_MARK_AND_SWEEP */
 
31617
 
 
31618
#line 1 "duk_heap_memory.c"
 
31619
/*
 
31620
 *  Memory allocation handling.
 
31621
 */
 
31622
 
 
31623
/* include removed: duk_internal.h */
 
31624
 
 
31625
/*
 
31626
 *  Helpers
 
31627
 *
 
31628
 *  The fast path checks are done within a macro to ensure "inlining"
 
31629
 *  while the slow path actions use a helper (which won't typically be
 
31630
 *  inlined in size optimized builds).
 
31631
 */
 
31632
 
 
31633
#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
 
31634
#define DUK__VOLUNTARY_PERIODIC_GC(heap)  do { \
 
31635
                (heap)->mark_and_sweep_trigger_counter--; \
 
31636
                if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
 
31637
                        duk__run_voluntary_gc(heap); \
 
31638
                } \
 
31639
        } while (0)
 
31640
 
 
31641
static void duk__run_voluntary_gc(duk_heap *heap) {
 
31642
        if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31643
                DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now");
 
31644
        } else {
 
31645
                int flags;
 
31646
                int rc;
 
31647
 
 
31648
                DUK_DPRINT("triggering voluntary mark-and-sweep");
 
31649
                flags = 0;
 
31650
                rc = duk_heap_mark_and_sweep(heap, flags);
 
31651
                DUK_UNREF(rc);
 
31652
        }
 
31653
}
 
31654
#else
 
31655
#define DUK__VOLUNTARY_PERIODIC_GC(heap)  /* no voluntary gc */
 
31656
#endif  /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
 
31657
 
 
31658
/*
 
31659
 *  Allocate memory with garbage collection
 
31660
 */
 
31661
 
 
31662
#ifdef DUK_USE_MARK_AND_SWEEP
 
31663
void *duk_heap_mem_alloc(duk_heap *heap, size_t size) {
 
31664
        void *res;
 
31665
        int rc;
 
31666
        int i;
 
31667
 
 
31668
        DUK_ASSERT(heap != NULL);
 
31669
        DUK_ASSERT_DISABLE(size >= 0);
 
31670
 
 
31671
        /*
 
31672
         *  Voluntary periodic GC (if enabled)
 
31673
         */
 
31674
 
 
31675
        DUK__VOLUNTARY_PERIODIC_GC(heap);
 
31676
 
 
31677
        /*
 
31678
         *  First attempt
 
31679
         */
 
31680
 
 
31681
#ifdef DUK_USE_GC_TORTURE
 
31682
        /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
 
31683
        if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31684
                DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails");
 
31685
                res = NULL;
 
31686
                DUK_UNREF(res);
 
31687
                goto skip_attempt;
 
31688
        }
 
31689
#endif
 
31690
        res = heap->alloc_func(heap->alloc_udata, size);
 
31691
        if (res || size == 0) {
 
31692
                /* for zero size allocations NULL is allowed */
 
31693
                return res;
 
31694
        }
 
31695
#ifdef DUK_USE_GC_TORTURE
 
31696
 skip_attempt:
 
31697
#endif
 
31698
 
 
31699
        DUK_DPRINT("first alloc attempt failed, attempt to gc and retry");
 
31700
 
 
31701
        /*
 
31702
         *  Avoid a GC if GC is already running.  This can happen at a late
 
31703
         *  stage in a GC when we try to e.g. resize the stringtable
 
31704
         *  or compact objects.
 
31705
         */
 
31706
 
 
31707
        if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31708
                DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %d", size);
 
31709
                return NULL;
 
31710
        }
 
31711
 
 
31712
        /*
 
31713
         *  Retry with several GC attempts.  Initial attempts are made without
 
31714
         *  emergency mode; later attempts use emergency mode which minimizes
 
31715
         *  memory allocations forcibly.
 
31716
         */
 
31717
 
 
31718
        for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
 
31719
                int flags;
 
31720
 
 
31721
                flags = 0;
 
31722
                if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
 
31723
                        flags |= DUK_MS_FLAG_EMERGENCY;
 
31724
                }
 
31725
 
 
31726
                rc = duk_heap_mark_and_sweep(heap, flags);
 
31727
                DUK_UNREF(rc);
 
31728
 
 
31729
                res = heap->alloc_func(heap->alloc_udata, size);
 
31730
                if (res) {
 
31731
                        DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %d), alloc size %d",
 
31732
                                   i + 1, size);
 
31733
                        return res;
 
31734
                }
 
31735
        }
 
31736
 
 
31737
        DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %d", size);
 
31738
        return NULL;
 
31739
}
 
31740
#else  /* DUK_USE_MARK_AND_SWEEP */
 
31741
/*
 
31742
 *  Compared to a direct macro expansion this wrapper saves a few
 
31743
 *  instructions because no heap dereferencing is required.
 
31744
 */
 
31745
void *duk_heap_mem_alloc(duk_heap *heap, size_t size) {
 
31746
        DUK_ASSERT(heap != NULL);
 
31747
        DUK_ASSERT_DISABLE(size >= 0);
 
31748
 
 
31749
        return heap->alloc_func(heap->alloc_udata, size);
 
31750
}
 
31751
#endif  /* DUK_USE_MARK_AND_SWEEP */
 
31752
 
 
31753
void *duk_heap_mem_alloc_zeroed(duk_heap *heap, size_t size) {
 
31754
        void *res;
 
31755
 
 
31756
        DUK_ASSERT(heap != NULL);
 
31757
        DUK_ASSERT_DISABLE(size >= 0);
 
31758
 
 
31759
        res = DUK_ALLOC(heap, size);
 
31760
        if (res) {
 
31761
                /* assume memset with zero size is OK */
 
31762
                DUK_MEMZERO(res, size);
 
31763
        }
 
31764
        return res;
 
31765
}
 
31766
 
 
31767
/*
 
31768
 *  Reallocate memory with garbage collection
 
31769
 */
 
31770
 
 
31771
#ifdef DUK_USE_MARK_AND_SWEEP
 
31772
void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, size_t newsize) {
 
31773
        void *res;
 
31774
        int rc;
 
31775
        int i;
 
31776
 
 
31777
        DUK_ASSERT(heap != NULL);
 
31778
        /* ptr may be NULL */
 
31779
        DUK_ASSERT_DISABLE(newsize >= 0);
 
31780
 
 
31781
        /*
 
31782
         *  Voluntary periodic GC (if enabled)
 
31783
         */
 
31784
 
 
31785
        DUK__VOLUNTARY_PERIODIC_GC(heap);
 
31786
 
 
31787
        /*
 
31788
         *  First attempt
 
31789
         */
 
31790
 
 
31791
#ifdef DUK_USE_GC_TORTURE
 
31792
        /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
 
31793
        if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31794
                DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails");
 
31795
                res = NULL;
 
31796
                DUK_UNREF(res);
 
31797
                goto skip_attempt;
 
31798
        }
 
31799
#endif
 
31800
        res = heap->realloc_func(heap->alloc_udata, ptr, newsize);
 
31801
        if (res || newsize == 0) {
 
31802
                /* for zero size allocations NULL is allowed */
 
31803
                return res;
 
31804
        }
 
31805
#ifdef DUK_USE_GC_TORTURE
 
31806
 skip_attempt:
 
31807
#endif
 
31808
 
 
31809
        DUK_DPRINT("first realloc attempt failed, attempt to gc and retry");
 
31810
 
 
31811
        /*
 
31812
         *  Avoid a GC if GC is already running.  See duk_heap_mem_alloc().
 
31813
         */
 
31814
 
 
31815
        if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31816
                DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %d", newsize);
 
31817
                return NULL;
 
31818
        }
 
31819
 
 
31820
        /*
 
31821
         *  Retry with several GC attempts.  Initial attempts are made without
 
31822
         *  emergency mode; later attempts use emergency mode which minimizes
 
31823
         *  memory allocations forcibly.
 
31824
         */
 
31825
 
 
31826
        for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
 
31827
                int flags;
 
31828
 
 
31829
                flags = 0;
 
31830
                if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
 
31831
                        flags |= DUK_MS_FLAG_EMERGENCY;
 
31832
                }
 
31833
 
 
31834
                rc = duk_heap_mark_and_sweep(heap, flags);
 
31835
                DUK_UNREF(rc);
 
31836
 
 
31837
                res = heap->realloc_func(heap->alloc_udata, ptr, newsize);
 
31838
                if (res) {
 
31839
                        DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %d), alloc size %d",
 
31840
                                   i + 1, newsize);
 
31841
                        return res;
 
31842
                }
 
31843
        }
 
31844
 
 
31845
        DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %d", newsize);
 
31846
        return NULL;
 
31847
}
 
31848
#else  /* DUK_USE_MARK_AND_SWEEP */
 
31849
/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
 
31850
void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, size_t newsize) {
 
31851
        DUK_ASSERT(heap != NULL);
 
31852
        /* ptr may be NULL */
 
31853
        DUK_ASSERT_DISABLE(newsize >= 0);
 
31854
 
 
31855
        return heap->realloc_func(heap->alloc_udata, ptr, newsize);
 
31856
}
 
31857
#endif  /* DUK_USE_MARK_AND_SWEEP */
 
31858
 
 
31859
/*
 
31860
 *  Reallocate memory with garbage collection, using a callback to provide
 
31861
 *  the current allocated pointer.  This variant is used when a mark-and-sweep
 
31862
 *  (e.g. finalizers) might change the original pointer.
 
31863
 */
 
31864
 
 
31865
#ifdef DUK_USE_MARK_AND_SWEEP
 
31866
void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, size_t newsize) {
 
31867
        void *res;
 
31868
        int rc;
 
31869
        int i;
 
31870
 
 
31871
        DUK_ASSERT(heap != NULL);
 
31872
        DUK_ASSERT_DISABLE(newsize >= 0);
 
31873
 
 
31874
        /*
 
31875
         *  Voluntary periodic GC (if enabled)
 
31876
         */
 
31877
 
 
31878
        DUK__VOLUNTARY_PERIODIC_GC(heap);
 
31879
 
 
31880
        /*
 
31881
         *  First attempt
 
31882
         */
 
31883
 
 
31884
#ifdef DUK_USE_GC_TORTURE
 
31885
        /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
 
31886
        if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31887
                DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails");
 
31888
                res = NULL;
 
31889
                DUK_UNREF(res);
 
31890
                goto skip_attempt;
 
31891
        }
 
31892
#endif
 
31893
        res = heap->realloc_func(heap->alloc_udata, cb(ud), newsize);
 
31894
        if (res || newsize == 0) {
 
31895
                /* for zero size allocations NULL is allowed */
 
31896
                return res;
 
31897
        }
 
31898
#ifdef DUK_USE_GC_TORTURE
 
31899
 skip_attempt:
 
31900
#endif
 
31901
 
 
31902
        DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry");
 
31903
 
 
31904
        /*
 
31905
         *  Avoid a GC if GC is already running.  See duk_heap_mem_alloc().
 
31906
         */
 
31907
 
 
31908
        if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
31909
                DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %d", newsize);
 
31910
                return NULL;
 
31911
        }
 
31912
 
 
31913
        /*
 
31914
         *  Retry with several GC attempts.  Initial attempts are made without
 
31915
         *  emergency mode; later attempts use emergency mode which minimizes
 
31916
         *  memory allocations forcibly.
 
31917
         */
 
31918
 
 
31919
        for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
 
31920
                int flags;
 
31921
 
 
31922
#ifdef DUK_USE_ASSERTIONS
 
31923
                void *ptr_pre;  /* ptr before mark-and-sweep */
 
31924
                void *ptr_post;
 
31925
#endif
 
31926
 
 
31927
#ifdef DUK_USE_ASSERTIONS
 
31928
                ptr_pre = cb(ud);
 
31929
#endif
 
31930
                flags = 0;
 
31931
                if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
 
31932
                        flags |= DUK_MS_FLAG_EMERGENCY;
 
31933
                }
 
31934
 
 
31935
                rc = duk_heap_mark_and_sweep(heap, flags);
 
31936
                DUK_UNREF(rc);
 
31937
#ifdef DUK_USE_ASSERTIONS
 
31938
                ptr_post = cb(ud);
 
31939
                if (ptr_pre != ptr_post) {
 
31940
                        /* useful for debugging */
 
31941
                        DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p", ptr_pre, ptr_post);
 
31942
                }
 
31943
#endif
 
31944
        
 
31945
                /* Note: key issue here is to re-lookup the base pointer on every attempt.
 
31946
                 * The pointer being reallocated may change after every mark-and-sweep.
 
31947
                 */
 
31948
 
 
31949
                res = heap->realloc_func(heap->alloc_udata, cb(ud), newsize);
 
31950
                if (res) {
 
31951
                        DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %d), alloc size %d",
 
31952
                                   i + 1, newsize);
 
31953
                        return res;
 
31954
                }
 
31955
        }
 
31956
 
 
31957
        DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %d", newsize);
 
31958
        return NULL;
 
31959
}
 
31960
#else  /* DUK_USE_MARK_AND_SWEEP */
 
31961
/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
 
31962
void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, size_t newsize) {
 
31963
        return heap->realloc_func(heap->alloc_udata, cb(ud), newsize);
 
31964
}
 
31965
#endif  /* DUK_USE_MARK_AND_SWEEP */
 
31966
 
 
31967
/*
 
31968
 *  Free memory
 
31969
 */
 
31970
 
 
31971
#ifdef DUK_USE_MARK_AND_SWEEP
 
31972
void duk_heap_mem_free(duk_heap *heap, void *ptr) {
 
31973
        DUK_ASSERT(heap != NULL);
 
31974
        /* ptr may be NULL */
 
31975
 
 
31976
        /* Must behave like a no-op with NULL and any pointer returned from
 
31977
         * malloc/realloc with zero size.
 
31978
         */
 
31979
        heap->free_func(heap->alloc_udata, ptr);
 
31980
 
 
31981
        /* Count free operations toward triggering a GC but never actually trigger
 
31982
         * a GC from a free.  Otherwise code which frees internal structures would
 
31983
         * need to put in NULLs at every turn to ensure the object is always in
 
31984
         * consistent state for a mark-and-sweep.
 
31985
         */
 
31986
#ifdef DUK_USE_VOLUNTARY_GC
 
31987
        heap->mark_and_sweep_trigger_counter--;
 
31988
#endif
 
31989
}
 
31990
#else
 
31991
/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
 
31992
void duk_heap_mem_free(duk_heap *heap, void *ptr) {
 
31993
        DUK_ASSERT(heap != NULL);
 
31994
        /* ptr may be NULL */
 
31995
 
 
31996
        /* Note: must behave like a no-op with NULL and any pointer
 
31997
         * returned from malloc/realloc with zero size.
 
31998
         */
 
31999
        heap->free_func(heap->alloc_udata, ptr);
 
32000
}
 
32001
#endif
 
32002
 
 
32003
/*
 
32004
 *  Checked variants
 
32005
 */
 
32006
 
 
32007
#ifdef DUK_USE_VERBOSE_ERRORS
 
32008
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size, const char *filename, int line) {
 
32009
#else
 
32010
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size) {
 
32011
#endif
 
32012
        void *res;
 
32013
 
 
32014
        DUK_ASSERT(thr != NULL);
 
32015
        DUK_ASSERT_DISABLE(size >= 0);
 
32016
 
 
32017
        res = DUK_ALLOC(thr->heap, size);
 
32018
        if (!res) {
 
32019
#ifdef DUK_USE_VERBOSE_ERRORS
 
32020
                DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
 
32021
#else
 
32022
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
 
32023
#endif
 
32024
        }
 
32025
        return res;
 
32026
}
 
32027
 
 
32028
#ifdef DUK_USE_VERBOSE_ERRORS
 
32029
void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, size_t size, const char *filename, int line) {
 
32030
#else
 
32031
void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, size_t size) {
 
32032
#endif
 
32033
        void *res;
 
32034
 
 
32035
        DUK_ASSERT(thr != NULL);
 
32036
        DUK_ASSERT_DISABLE(size >= 0);
 
32037
 
 
32038
        res = DUK_ALLOC(thr->heap, size);
 
32039
        if (!res) {
 
32040
#ifdef DUK_USE_VERBOSE_ERRORS
 
32041
                DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
 
32042
#else
 
32043
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
 
32044
#endif
 
32045
        }
 
32046
        /* assume memset with zero size is OK */
 
32047
        DUK_MEMZERO(res, size);
 
32048
        return res;
 
32049
}
 
32050
 
 
32051
#ifdef DUK_USE_VERBOSE_ERRORS
 
32052
void *duk_heap_mem_realloc_checked(duk_hthread *thr, void *ptr, size_t newsize, const char *filename, int line) {
 
32053
#else
 
32054
void *duk_heap_mem_realloc_checked(duk_hthread *thr, void *ptr, size_t newsize) {
 
32055
#endif
 
32056
        void *res;
 
32057
 
 
32058
        DUK_ASSERT(thr != NULL);
 
32059
        /* ptr may be NULL */
 
32060
        DUK_ASSERT_DISABLE(newsize >= 0);
 
32061
 
 
32062
        res = DUK_REALLOC(thr->heap, ptr, newsize);
 
32063
        if (!res) {
 
32064
#ifdef DUK_USE_VERBOSE_ERRORS
 
32065
                DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
 
32066
#else
 
32067
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
 
32068
#endif
 
32069
        }
 
32070
        return res;
 
32071
}
 
32072
 
 
32073
#ifdef DUK_USE_VERBOSE_ERRORS
 
32074
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize, const char *filename, int line) {
 
32075
#else
 
32076
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize) {
 
32077
#endif
 
32078
        void *res;
 
32079
        DUK_ASSERT(thr != NULL);
 
32080
        DUK_ASSERT_DISABLE(newsize >= 0);
 
32081
 
 
32082
        res = DUK_REALLOC_INDIRECT(thr->heap, cb, ud, newsize);
 
32083
        if (!res) {
 
32084
#ifdef DUK_USE_VERBOSE_ERRORS
 
32085
                DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
 
32086
#else
 
32087
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
 
32088
#endif
 
32089
        }
 
32090
        return res;
 
32091
}
 
32092
 
 
32093
/* Note: no need for duk_heap_mem_free_checked(), as free must not fail.
 
32094
 * There is a DUK_FREE_CHECKED() macro just in case, though.
 
32095
 */
 
32096
 
 
32097
#line 1 "duk_heap_misc.c"
 
32098
/*
 
32099
 *  Support functions for duk_heap.
 
32100
 */
 
32101
 
 
32102
/* include removed: duk_internal.h */
 
32103
 
 
32104
#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
 
32105
/* arbitrary remove only works with double linked heap, and is only required by
 
32106
 * reference counting so far.
 
32107
 */
 
32108
void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
 
32109
        DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
 
32110
 
 
32111
        if (DUK_HEAPHDR_GET_PREV(hdr)) {
 
32112
                DUK_HEAPHDR_SET_NEXT(DUK_HEAPHDR_GET_PREV(hdr), DUK_HEAPHDR_GET_NEXT(hdr));
 
32113
        } else {
 
32114
                heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(hdr);
 
32115
        }
 
32116
        if (DUK_HEAPHDR_GET_NEXT(hdr)) {
 
32117
                DUK_HEAPHDR_SET_PREV(DUK_HEAPHDR_GET_NEXT(hdr), DUK_HEAPHDR_GET_PREV(hdr));
 
32118
        } else {
 
32119
                ;
 
32120
        }
 
32121
}
 
32122
#endif
 
32123
 
 
32124
void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
 
32125
        DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
 
32126
 
 
32127
#ifdef DUK_USE_DOUBLE_LINKED_HEAP
 
32128
        if (heap->heap_allocated) {
 
32129
                DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap->heap_allocated) == NULL);
 
32130
                DUK_HEAPHDR_SET_PREV(heap->heap_allocated, hdr);
 
32131
        }
 
32132
        DUK_HEAPHDR_SET_PREV(hdr, NULL);
 
32133
#endif
 
32134
        DUK_HEAPHDR_SET_NEXT(hdr, heap->heap_allocated);
 
32135
        heap->heap_allocated = hdr;
 
32136
}
 
32137
 
 
32138
#ifdef DUK_USE_INTERRUPT_COUNTER
 
32139
void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
 
32140
        /* Copy currently active interrupt counter from the active thread
 
32141
         * back to the heap structure.  It doesn't need to be copied to
 
32142
         * the target thread, as the bytecode executor does that when it
 
32143
         * resumes execution for a new thread.
 
32144
         */
 
32145
        if (heap->curr_thread != NULL) {
 
32146
                heap->interrupt_counter = heap->curr_thread->interrupt_counter;
 
32147
        }
 
32148
        heap->curr_thread = new_thr;  /* may be NULL */
 
32149
}
 
32150
#endif  /* DUK_USE_INTERRUPT_COUNTER */
 
32151
#line 1 "duk_heap_refcount.c"
 
32152
/*
 
32153
 *  Reference counting implementation.
 
32154
 */
 
32155
 
 
32156
/* include removed: duk_internal.h */
 
32157
 
 
32158
#ifdef DUK_USE_REFERENCE_COUNTING
 
32159
 
 
32160
#ifndef DUK_USE_DOUBLE_LINKED_HEAP
 
32161
#error internal error, reference counting requires a double linked heap
 
32162
#endif
 
32163
 
 
32164
/*
 
32165
 *  Misc
 
32166
 */
 
32167
 
 
32168
static void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
 
32169
        /* tail insert: don't disturb head in case refzero is running */
 
32170
 
 
32171
        if (heap->refzero_list != NULL) {
 
32172
                duk_heaphdr *hdr_prev;
 
32173
 
 
32174
                hdr_prev = heap->refzero_list_tail;
 
32175
                DUK_ASSERT(hdr_prev != NULL);
 
32176
                DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(hdr_prev) == NULL);
 
32177
 
 
32178
                DUK_HEAPHDR_SET_NEXT(hdr, NULL);
 
32179
                DUK_HEAPHDR_SET_PREV(hdr, hdr_prev);
 
32180
                DUK_HEAPHDR_SET_NEXT(hdr_prev, hdr);
 
32181
                heap->refzero_list_tail = hdr;
 
32182
        } else {
 
32183
                DUK_ASSERT(heap->refzero_list_tail == NULL);
 
32184
                DUK_HEAPHDR_SET_NEXT(hdr, NULL);
 
32185
                DUK_HEAPHDR_SET_PREV(hdr, NULL);
 
32186
                heap->refzero_list = hdr;
 
32187
                heap->refzero_list_tail = hdr;
 
32188
        }
 
32189
}
 
32190
 
 
32191
/*
 
32192
 *  Heap object refcount finalization.
 
32193
 *
 
32194
 *  When an object is about to be freed, all other objects it refers to must
 
32195
 *  be decref'd.  Refcount finalization does NOT free the object or its inner
 
32196
 *  allocations (mark-and-sweep shares these helpers), it just manipulates
 
32197
 *  the refcounts.
 
32198
 *
 
32199
 *  Note that any of the decref's may cause a refcount to drop to zero, BUT
 
32200
 *  it will not be processed inline; instead, because refzero is already
 
32201
 *  running, the objects will just be queued to refzero list and processed
 
32202
 *  later.  This eliminates C recursion.
 
32203
 */
 
32204
 
 
32205
static void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
 
32206
        duk_uint_fast32_t i;
 
32207
 
 
32208
        DUK_ASSERT(h);
 
32209
        DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
 
32210
 
 
32211
        /* XXX: better to get base and walk forwards? */
 
32212
 
 
32213
        for (i = 0; i < h->e_used; i++) {
 
32214
                duk_hstring *key = DUK_HOBJECT_E_GET_KEY(h, i);
 
32215
                if (!key) {
 
32216
                        continue;
 
32217
                }
 
32218
                duk_heap_heaphdr_decref(thr, (duk_heaphdr *) key);
 
32219
                if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h, i)) {
 
32220
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(h, i));
 
32221
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(h, i));
 
32222
                } else {
 
32223
                        duk_heap_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(h, i));
 
32224
                }
 
32225
        }
 
32226
 
 
32227
        for (i = 0; i < h->a_size; i++) {
 
32228
                duk_heap_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(h, i));
 
32229
        }
 
32230
 
 
32231
        /* hash part is a 'weak reference' and does not contribute */
 
32232
 
 
32233
        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) h->prototype);
 
32234
 
 
32235
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
 
32236
                duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
 
32237
                duk_tval *tv, *tv_end;
 
32238
                duk_hobject **funcs, **funcs_end;
 
32239
 
 
32240
                DUK_ASSERT(f->data != NULL);  /* compiled functions must be created 'atomically' */
 
32241
 
 
32242
                tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(f);
 
32243
                tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(f);
 
32244
                while (tv < tv_end) {
 
32245
                        duk_heap_tval_decref(thr, tv);
 
32246
                        tv++;
 
32247
                }
 
32248
 
 
32249
                funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(f);
 
32250
                funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(f);
 
32251
                while (funcs < funcs_end) {
 
32252
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
 
32253
                        funcs++;
 
32254
                }
 
32255
 
 
32256
                duk_heap_heaphdr_decref(thr, (duk_heaphdr *) f->data);
 
32257
        } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
 
32258
                duk_hnativefunction *f = (duk_hnativefunction *) h;
 
32259
                DUK_UNREF(f);
 
32260
                /* nothing to finalize */
 
32261
        } else if (DUK_HOBJECT_IS_THREAD(h)) {
 
32262
                duk_hthread *t = (duk_hthread *) h;
 
32263
                duk_tval *tv;
 
32264
 
 
32265
                tv = t->valstack;
 
32266
                while (tv < t->valstack_end) {
 
32267
                        duk_heap_tval_decref(thr, tv);
 
32268
                        tv++;
 
32269
                }
 
32270
 
 
32271
                for (i = 0; i < t->callstack_top; i++) {
 
32272
                        duk_activation *act = &t->callstack[i];
 
32273
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->func);
 
32274
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->var_env);
 
32275
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->lex_env);
 
32276
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
32277
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->prev_caller);
 
32278
#endif
 
32279
                }
 
32280
 
 
32281
#if 0  /* nothing now */
 
32282
                for (i = 0; i < t->catchstack_top; i++) {
 
32283
                        duk_catcher *cat = &t->catchstack[i];
 
32284
                }
 
32285
#endif
 
32286
 
 
32287
                for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
32288
                        duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->builtins[i]);
 
32289
                }
 
32290
 
 
32291
                duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->resumer);
 
32292
        }
 
32293
}
 
32294
 
 
32295
void duk_heap_refcount_finalize_heaphdr(duk_hthread *thr, duk_heaphdr *hdr) {
 
32296
        DUK_ASSERT(hdr);
 
32297
 
 
32298
        switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
 
32299
        case DUK_HTYPE_OBJECT:
 
32300
                duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
 
32301
                break;
 
32302
        case DUK_HTYPE_BUFFER:
 
32303
                /* nothing to finalize */
 
32304
                break;
 
32305
        case DUK_HTYPE_STRING:
 
32306
                /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */
 
32307
        default:
 
32308
                DUK_UNREACHABLE();
 
32309
        }
 
32310
}
 
32311
 
 
32312
/*
 
32313
 *  Refcount memory freeing loop.
 
32314
 *
 
32315
 *  Frees objects in the refzero_pending list until the list becomes
 
32316
 *  empty.  When an object is freed, its references get decref'd and
 
32317
 *  may cause further objects to be queued for freeing.
 
32318
 *
 
32319
 *  This could be expanded to allow incremental freeing: just bail out
 
32320
 *  early and resume at a future alloc/decref/refzero.
 
32321
 */
 
32322
 
 
32323
static void duk__refzero_free_pending(duk_hthread *thr) {
 
32324
        duk_heaphdr *h1, *h2;
 
32325
        duk_heap *heap;
 
32326
        int count = 0;
 
32327
 
 
32328
        DUK_ASSERT(thr != NULL);
 
32329
        DUK_ASSERT(thr->heap != NULL);
 
32330
        heap = thr->heap;
 
32331
        DUK_ASSERT(heap != NULL);
 
32332
 
 
32333
        /*
 
32334
         *  Detect recursive invocation
 
32335
         */
 
32336
 
 
32337
        if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
 
32338
                DUK_DDDPRINT("refzero free running, skip run");
 
32339
                return;
 
32340
        }
 
32341
 
 
32342
        /*
 
32343
         *  Churn refzero_list until empty
 
32344
         */
 
32345
 
 
32346
        DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
 
32347
        while (heap->refzero_list) {
 
32348
                duk_hobject *obj;
 
32349
                int rescued = 0;
 
32350
 
 
32351
                /*
 
32352
                 *  Pick an object from the head (don't remove yet).
 
32353
                 */
 
32354
 
 
32355
                h1 = heap->refzero_list;
 
32356
                obj = (duk_hobject *) h1;
 
32357
                DUK_DDPRINT("refzero processing %p: %!O", h1, h1);
 
32358
                DUK_ASSERT(DUK_HEAPHDR_GET_PREV(h1) == NULL);
 
32359
                DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT);  /* currently, always the case */
 
32360
 
 
32361
                /*
 
32362
                 *  Finalizer check.
 
32363
                 *
 
32364
                 *  Note: running a finalizer may have arbitrary side effects, e.g.
 
32365
                 *  queue more objects on refzero_list (tail), or even trigger a
 
32366
                 *  mark-and-sweep.
 
32367
                 *
 
32368
                 *  Note: quick reject check should match vast majority of
 
32369
                 *  objects and must be safe (not throw any errors, ever).
 
32370
                 */
 
32371
 
 
32372
                /* FIXME: If object has FINALIZED, it was finalized by mark-and-sweep on
 
32373
                 * its previous run.  Any point in running finalizer again here?  If
 
32374
                 * finalization semantics is changed so that finalizer is only run once,
 
32375
                 * checking for FINALIZED would happen here.
 
32376
                 */
 
32377
 
 
32378
                if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
 
32379
                        DUK_DDDPRINT("object has a finalizer, run it");
 
32380
 
 
32381
                        DUK_ASSERT(h1->h_refcount == 0);
 
32382
                        h1->h_refcount++;  /* bump refcount to prevent refzero during finalizer processing */
 
32383
 
 
32384
                        duk_hobject_run_finalizer(thr, obj);  /* must never longjmp */
 
32385
 
 
32386
                        h1->h_refcount--;  /* remove artificial bump */
 
32387
                        DUK_ASSERT_DISABLE(h1->h_refcount >= 0);  /* refcount is unsigned, so always true */
 
32388
 
 
32389
                        if (h1->h_refcount != 0) {
 
32390
                                DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued");
 
32391
                                rescued = 1;
 
32392
                        } else {
 
32393
                                DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed");
 
32394
                        }
 
32395
                }
 
32396
 
 
32397
                /* Refzero head is still the same.  This is the case even if finalizer
 
32398
                 * inserted more refzero objects; they are inserted to the tail.
 
32399
                 */
 
32400
                DUK_ASSERT(h1 == heap->refzero_list);
 
32401
 
 
32402
                /*
 
32403
                 *  Remove the object from the refzero list.  This cannot be done
 
32404
                 *  before a possible finalizer has been executed; the finalizer
 
32405
                 *  may trigger a mark-and-sweep, and mark-and-sweep must be able
 
32406
                 *  to traverse a complete refzero_list.
 
32407
                 */
 
32408
 
 
32409
                h2 = DUK_HEAPHDR_GET_NEXT(h1);
 
32410
                if (h2) {
 
32411
                        DUK_HEAPHDR_SET_PREV(h2, NULL);  /* not strictly necessary */
 
32412
                        heap->refzero_list = h2;
 
32413
                } else {
 
32414
                        heap->refzero_list = NULL;
 
32415
                        heap->refzero_list_tail = NULL;
 
32416
                }
 
32417
 
 
32418
                /*
 
32419
                 *  Rescue or free.
 
32420
                 */
 
32421
 
 
32422
                if (rescued) {
 
32423
                        /* yes -> move back to heap allocated */
 
32424
                        DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1);
 
32425
                        DUK_HEAPHDR_SET_PREV(h1, NULL);
 
32426
                        DUK_HEAPHDR_SET_NEXT(h1, heap->heap_allocated);
 
32427
                        heap->heap_allocated = h1;
 
32428
                } else {
 
32429
                        /* no -> decref members, then free */
 
32430
                        duk__refcount_finalize_hobject(thr, obj);
 
32431
                        duk_heap_free_heaphdr_raw(heap, h1);
 
32432
                }
 
32433
 
 
32434
                count++;
 
32435
        }
 
32436
        DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
 
32437
 
 
32438
        DUK_DDDPRINT("refzero processed %d objects", count);
 
32439
 
 
32440
        /*
 
32441
         *  Once the whole refzero cascade has been freed, check for
 
32442
         *  a voluntary mark-and-sweep.
 
32443
         */
 
32444
 
 
32445
#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
 
32446
        /* 'count' is more or less comparable to normal trigger counter update
 
32447
         * which happens in memory block (re)allocation.
 
32448
         */
 
32449
        heap->mark_and_sweep_trigger_counter -= count;
 
32450
        if (heap->mark_and_sweep_trigger_counter <= 0) {
 
32451
                int rc;
 
32452
                int emergency = 0;
 
32453
                DUK_DPRINT("refcount triggering mark-and-sweep");
 
32454
                rc = duk_heap_mark_and_sweep(heap, emergency);
 
32455
                DUK_UNREF(rc);
 
32456
                DUK_DPRINT("refcount triggered mark-and-sweep => rc %d", rc);
 
32457
        }
 
32458
#endif  /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
 
32459
}
 
32460
 
 
32461
/*
 
32462
 *  Incref and decref functions.
 
32463
 *
 
32464
 *  Decref may trigger immediate refzero handling, which may free and finalize
 
32465
 *  an arbitrary number of objects.
 
32466
 *  
 
32467
 */
 
32468
 
 
32469
void duk_heap_tval_incref(duk_tval *tv) {
 
32470
#if 0
 
32471
        DUK_DDDPRINT("tval incref %p (%d->%d): %!T",
 
32472
                     (void *) tv,
 
32473
                     (tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv)->h_refcount : 0),
 
32474
                     (tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv)->h_refcount + 1 : 0),
 
32475
                     tv);
 
32476
#endif
 
32477
 
 
32478
        if (!tv) {
 
32479
                return;
 
32480
        }
 
32481
 
 
32482
        if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
 
32483
                duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
 
32484
                if (h) {
 
32485
                        DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
 
32486
                        DUK_ASSERT_DISABLE(h->h_refcount >= 0);
 
32487
                        h->h_refcount++;
 
32488
                }
 
32489
        }
 
32490
}
 
32491
 
 
32492
void duk_heap_tval_decref(duk_hthread *thr, duk_tval *tv) {
 
32493
#if 0
 
32494
        DUK_DDDPRINT("tval decref %p (%d->%d): %!T",
 
32495
                     (void *) tv,
 
32496
                     (tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv)->h_refcount : 0),
 
32497
                     (tv != NULL && DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv)->h_refcount - 1 : 0),
 
32498
                     tv);
 
32499
#endif
 
32500
 
 
32501
        if (!tv) {
 
32502
                return;
 
32503
        }
 
32504
 
 
32505
        if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
 
32506
                duk_heap_heaphdr_decref(thr, DUK_TVAL_GET_HEAPHDR(tv));
 
32507
        }
 
32508
}
 
32509
 
 
32510
void duk_heap_heaphdr_incref(duk_heaphdr *h) {
 
32511
#if 0
 
32512
        DUK_DDDPRINT("heaphdr incref %p (%d->%d): %!O",
 
32513
                     (void *) h,
 
32514
                     (h != NULL ? h->h_refcount : 0),
 
32515
                     (h != NULL ? h->h_refcount + 1 : 0),
 
32516
                     h);
 
32517
#endif
 
32518
 
 
32519
        if (!h) {
 
32520
                return;
 
32521
        }
 
32522
        DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
 
32523
        DUK_ASSERT_DISABLE(h->h_refcount >= 0);
 
32524
 
 
32525
        h->h_refcount++;
 
32526
}
 
32527
 
 
32528
void duk_heap_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
 
32529
        duk_heap *heap;
 
32530
 
 
32531
#if 0
 
32532
        DUK_DDDPRINT("heaphdr decref %p (%d->%d): %!O",
 
32533
                     (void *) h,
 
32534
                     (h != NULL ? h->h_refcount : 0),
 
32535
                     (h != NULL ? h->h_refcount - 1 : 0),
 
32536
                     h);
 
32537
#endif
 
32538
 
 
32539
        DUK_ASSERT(thr != NULL);
 
32540
        DUK_ASSERT(thr->heap != NULL);
 
32541
 
 
32542
        if (!h) {
 
32543
                return;
 
32544
        }
 
32545
        DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
 
32546
        DUK_ASSERT(h->h_refcount >= 1);
 
32547
 
 
32548
        if (--h->h_refcount != 0) {
 
32549
                return;
 
32550
        }
 
32551
 
 
32552
        heap = thr->heap;
 
32553
        DUK_DDDPRINT("refzero %p: %!O", (void *) h, h);
 
32554
 
 
32555
#ifdef DUK_USE_MARK_AND_SWEEP
 
32556
        /*
 
32557
         *  If mark-and-sweep is running, don't process 'refzero' situations at all.
 
32558
         *  They may happen because mark-and-sweep needs to finalize refcounts for
 
32559
         *  each object it sweeps.  Otherwise the target objects of swept objects
 
32560
         *  would have incorrect refcounts.
 
32561
         *
 
32562
         *  Note: mark-and-sweep could use a separate decref handler to avoid coming
 
32563
         *  here at all.  However, mark-and-sweep may also call finalizers, which
 
32564
         *  can do arbitrary operations and would use this decref variant anyway.
 
32565
         */
 
32566
        if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
 
32567
                DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h);
 
32568
                return;
 
32569
        }
 
32570
#endif
 
32571
 
 
32572
        switch (DUK_HEAPHDR_GET_TYPE(h)) {
 
32573
        case DUK_HTYPE_STRING:
 
32574
                /*
 
32575
                 *  Strings have no internal references but do have "weak"
 
32576
                 *  references in the string cache.  Also note that strings
 
32577
                 *  are not on the heap_allocated list like other heap
 
32578
                 *  elements.
 
32579
                 */
 
32580
 
 
32581
                duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
 
32582
                duk_heap_string_remove(heap, (duk_hstring *) h);
 
32583
                duk_heap_free_heaphdr_raw(heap, h);
 
32584
                break;
 
32585
 
 
32586
        case DUK_HTYPE_OBJECT:
 
32587
                /*
 
32588
                 *  Objects have internal references.  Must finalize through
 
32589
                 *  the "refzero" work list.
 
32590
                 */
 
32591
 
 
32592
                duk_heap_remove_any_from_heap_allocated(heap, h);
 
32593
                duk__queue_refzero(heap, h);
 
32594
                duk__refzero_free_pending(thr);
 
32595
                break;
 
32596
 
 
32597
        case DUK_HTYPE_BUFFER:
 
32598
                /*
 
32599
                 *  Buffers have no internal references.  However, a dynamic
 
32600
                 *  buffer has a separate allocation for the buffer.  This is
 
32601
                 *  freed by duk_heap_free_heaphdr_raw().
 
32602
                 */
 
32603
 
 
32604
                duk_heap_remove_any_from_heap_allocated(heap, h);
 
32605
                duk_heap_free_heaphdr_raw(heap, h);
 
32606
                break;
 
32607
 
 
32608
        default:
 
32609
                DUK_DPRINT("invalid heap type in decref: %d", (int) DUK_HEAPHDR_GET_TYPE(h));
 
32610
                DUK_UNREACHABLE();
 
32611
        }
 
32612
}
 
32613
 
 
32614
#else
 
32615
 
 
32616
/* no refcounting */
 
32617
 
 
32618
#endif  /* DUK_USE_REFERENCE_COUNTING */
 
32619
 
 
32620
#line 1 "duk_heap_stringcache.c"
 
32621
/*
 
32622
 *  String cache.
 
32623
 *
 
32624
 *  Provides a cache to optimize indexed string lookups.  The cache keeps
 
32625
 *  track of (byte offset, char offset) states for a fixed number of strings.
 
32626
 *  Otherwise we'd need to scan from either end of the string, as we store
 
32627
 *  strings in (extended) UTF-8.
 
32628
 */
 
32629
 
 
32630
/* include removed: duk_internal.h */
 
32631
 
 
32632
/*
 
32633
 *  Delete references to given hstring from the heap string cache.
 
32634
 *
 
32635
 *  String cache references are 'weak': they are not counted towards
 
32636
 *  reference counts, nor serve as roots for mark-and-sweep.  When an
 
32637
 *  object is about to be freed, such references need to be removed.
 
32638
 */
 
32639
 
 
32640
void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
 
32641
        int i;
 
32642
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
32643
                duk_strcache *c = &heap->strcache[i];
 
32644
                if (c->h == h) {
 
32645
                        DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
 
32646
                                    (void *) h, (void *) heap);
 
32647
                        c->h = NULL;
 
32648
 
 
32649
                        /* XXX: the string shouldn't appear twice, but we now loop to the
 
32650
                         * end anyway; if fixed, add a looping assertion to ensure there
 
32651
                         * is no duplicate.
 
32652
                         */
 
32653
                }
 
32654
        }
 
32655
}
 
32656
 
 
32657
/*
 
32658
 *  String scanning helpers
 
32659
 */
 
32660
 
 
32661
static duk_uint8_t *duk__scan_forwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint32_t n) {
 
32662
        while (n > 0) {
 
32663
                for (;;) {
 
32664
                        p++;
 
32665
                        if (p >= q) {
 
32666
                                return NULL;
 
32667
                        }
 
32668
                        if ((*p & 0xc0) != 0x80) {
 
32669
                                break;
 
32670
                        }
 
32671
                }
 
32672
                n--;
 
32673
        }
 
32674
        return p;
 
32675
}
 
32676
 
 
32677
static duk_uint8_t *duk__scan_backwards(duk_uint8_t *p, duk_uint8_t *q, duk_uint32_t n) {
 
32678
        while (n > 0) {
 
32679
                for (;;) {
 
32680
                        p--;
 
32681
                        if (p < q) {
 
32682
                                return NULL;
 
32683
                        }
 
32684
                        if ((*p & 0xc0) != 0x80) {
 
32685
                                break;
 
32686
                        }
 
32687
                }
 
32688
                n--;
 
32689
        }
 
32690
        return p;
 
32691
}
 
32692
 
 
32693
/*
 
32694
 *  Convert char offset to byte offset
 
32695
 *
 
32696
 *  Avoid using the string cache if possible: for ASCII strings byte and
 
32697
 *  char offsets are equal and for short strings direct scanning may be
 
32698
 *  better than using the string cache (which may evict a more important
 
32699
 *  entry).
 
32700
 */
 
32701
 
 
32702
/* FIXME: typing throughout */
 
32703
 
 
32704
duk_uint32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint32_t char_offset) {
 
32705
        duk_heap *heap;
 
32706
        duk_strcache *sce;
 
32707
        duk_uint32_t byte_offset;
 
32708
        int i;
 
32709
        int use_cache;
 
32710
        duk_uint32_t dist_start, dist_end, dist_sce;
 
32711
        duk_uint8_t *p_start;
 
32712
        duk_uint8_t *p_end;
 
32713
        duk_uint8_t *p_found;
 
32714
 
 
32715
        if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
 
32716
                goto error;
 
32717
        }
 
32718
 
 
32719
        /*
 
32720
         *  For ASCII strings, the answer is simple.
 
32721
         */
 
32722
 
 
32723
        if (DUK_HSTRING_IS_ASCII(h)) {
 
32724
                /* clen == blen -> pure ascii */
 
32725
                return char_offset;
 
32726
        }
 
32727
 
 
32728
        /*
 
32729
         *  For non-ASCII strings, we need to scan forwards or backwards
 
32730
         *  from some starting point.  The starting point may be the start
 
32731
         *  or end of the string, or some cached midpoint in the string
 
32732
         *  cache.
 
32733
         *
 
32734
         *  For "short" strings we simply scan without checking or updating
 
32735
         *  the cache.  For longer strings we check and update the cache as
 
32736
         *  necessary, inserting a new cache entry if none exists.
 
32737
         */
 
32738
 
 
32739
        DUK_DDDPRINT("non-ascii string %p, char_offset=%d, clen=%d, blen=%d",
 
32740
                     (void *) h, char_offset, DUK_HSTRING_GET_CHARLEN(h),
 
32741
                     DUK_HSTRING_GET_BYTELEN(h));
 
32742
 
 
32743
        heap = thr->heap;
 
32744
        sce = NULL;
 
32745
        use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
 
32746
 
 
32747
        if (use_cache) {
 
32748
#ifdef DUK_USE_DDDEBUG
 
32749
                DUK_DDDPRINT("stringcache before char2byte (using cache):");
 
32750
                for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
32751
                        duk_strcache *c = &heap->strcache[i];
 
32752
                        DUK_DDDPRINT("  [%d] -> h=%p, cidx=%d, bidx=%d", i, c->h, c->cidx, c->bidx);
 
32753
                }
 
32754
#endif
 
32755
 
 
32756
                for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
32757
                        duk_strcache *c = &heap->strcache[i];
 
32758
 
 
32759
                        if (c->h == h) {
 
32760
                                sce = c;
 
32761
                                break;
 
32762
                        }
 
32763
                }
 
32764
        }
 
32765
 
 
32766
        /*
 
32767
         *  Scan from shortest distance:
 
32768
         *    - start of string
 
32769
         *    - end of string
 
32770
         *    - cache entry (if exists)
 
32771
         */
 
32772
 
 
32773
        DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
 
32774
        dist_start = char_offset;
 
32775
        dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
 
32776
        dist_sce = 0; DUK_UNREF(dist_sce);  /* initialize for debug prints, needed if sce==NULL */
 
32777
 
 
32778
        p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
 
32779
        p_end = (duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
 
32780
        p_found = NULL;
 
32781
 
 
32782
        if (sce) {
 
32783
                if (char_offset >= sce->cidx) {
 
32784
                        dist_sce = char_offset - sce->cidx;
 
32785
                        if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
 
32786
                                DUK_DDDPRINT("non-ascii string, use_cache=%d, sce=%p:%d:%d, "
 
32787
                                             "dist_start=%d, dist_end=%d, dist_sce=%d => "
 
32788
                                             "scan forwards from sce",
 
32789
                                             (int) use_cache, (sce ? sce->h : NULL), (sce ? (int) sce->cidx : (int) -1),
 
32790
                                             (sce ? (int) sce->bidx : (int) -1), (int) dist_start, (int) dist_end, (int) dist_sce);
 
32791
 
 
32792
                                p_found = duk__scan_forwards(p_start + sce->bidx,
 
32793
                                                             p_end,
 
32794
                                                             dist_sce);
 
32795
                                goto scan_done;
 
32796
                        }
 
32797
                } else {
 
32798
                        dist_sce = sce->cidx - char_offset;
 
32799
                        if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
 
32800
                                DUK_DDDPRINT("non-ascii string, use_cache=%d, sce=%p:%d:%d, "
 
32801
                                             "dist_start=%d, dist_end=%d, dist_sce=%d => "
 
32802
                                             "scan backwards from sce",
 
32803
                                             (int) use_cache, (sce ? sce->h : NULL), (sce ? (int) sce->cidx : (int) -1),
 
32804
                                             (sce ? (int) sce->bidx : (int) -1), (int) dist_start, (int) dist_end, (int) dist_sce);
 
32805
 
 
32806
                                p_found = duk__scan_backwards(p_start + sce->bidx,
 
32807
                                                              p_start,
 
32808
                                                              dist_sce);
 
32809
                                goto scan_done;
 
32810
                        }
 
32811
                }
 
32812
        }
 
32813
 
 
32814
        /* no sce, or sce scan not best */
 
32815
 
 
32816
        if (dist_start <= dist_end) {
 
32817
                DUK_DDDPRINT("non-ascii string, use_cache=%d, sce=%p:%d:%d, "
 
32818
                             "dist_start=%d, dist_end=%d, dist_sce=%d => "
 
32819
                             "scan forwards from string start",
 
32820
                             (int) use_cache, (sce ? sce->h : NULL), (sce ? (int) sce->cidx : (int) -1),
 
32821
                             (sce ? (int) sce->bidx : (int) -1), (int) dist_start, (int) dist_end, (int) dist_sce);
 
32822
 
 
32823
                p_found = duk__scan_forwards(p_start,
 
32824
                                             p_end,
 
32825
                                             dist_start);
 
32826
        } else {
 
32827
                DUK_DDDPRINT("non-ascii string, use_cache=%d, sce=%p:%d:%d, "
 
32828
                             "dist_start=%d, dist_end=%d, dist_sce=%d => "
 
32829
                             "scan backwards from string end",
 
32830
                             (int) use_cache, (sce ? sce->h : NULL), (sce ? (int) sce->cidx : (int) -1),
 
32831
                             (sce ? (int) sce->bidx : (int) -1), (int) dist_start, (int) dist_end, (int) dist_sce);
 
32832
 
 
32833
                p_found = duk__scan_backwards(p_end,
 
32834
                                              p_start,
 
32835
                                              dist_end);
 
32836
        }
 
32837
 
 
32838
 scan_done:
 
32839
 
 
32840
        if (!p_found) {
 
32841
                /* Scan error: this shouldn't normally happen; it could happen if
 
32842
                 * string is not valid UTF-8 data, and clen/blen are not consistent
 
32843
                 * with the scanning algorithm.
 
32844
                 */
 
32845
                goto error;
 
32846
        }
 
32847
 
 
32848
        DUK_ASSERT(p_found >= p_start);
 
32849
        DUK_ASSERT(p_found <= p_end);  /* may be equal */
 
32850
        byte_offset = (duk_uint32_t) (p_found - p_start);
 
32851
 
 
32852
        DUK_DDDPRINT("-> string %p, cidx %d -> bidx %d", (void *) h, char_offset, byte_offset);
 
32853
 
 
32854
        /*
 
32855
         *  Update cache entry (allocating if necessary), and move the
 
32856
         *  cache entry to the first place (in an "LRU" policy).
 
32857
         */
 
32858
        
 
32859
        if (use_cache) {
 
32860
                /* update entry, allocating if necessary */
 
32861
                if (!sce) {
 
32862
                        sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1;  /* take last entry */
 
32863
                        sce->h = h;
 
32864
                }
 
32865
                DUK_ASSERT(sce != NULL);
 
32866
                sce->bidx = (duk_uint32_t) (p_found - p_start);
 
32867
                sce->cidx = char_offset;
 
32868
 
 
32869
                /* LRU: move our entry to first */
 
32870
                if (sce > &heap->strcache[0]) {
 
32871
                        /*
 
32872
                         *   A                  C
 
32873
                         *   B                  A
 
32874
                         *   C <- sce    ==>    B
 
32875
                         *   D                  D
 
32876
                         */
 
32877
                        duk_strcache tmp;
 
32878
 
 
32879
                        tmp = *sce;
 
32880
                        DUK_MEMMOVE((void *) (&heap->strcache[1]),
 
32881
                                    (void *) (&heap->strcache[0]),
 
32882
                                    (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
 
32883
                        heap->strcache[0] = tmp;
 
32884
 
 
32885
                        /* 'sce' points to the wrong entry here, but is no longer used */
 
32886
                }
 
32887
#ifdef DUK_USE_DDDEBUG
 
32888
                DUK_DDDPRINT("stringcache after char2byte (using cache):");
 
32889
                for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
 
32890
                        duk_strcache *c = &heap->strcache[i];
 
32891
                        DUK_DDDPRINT("  [%d] -> h=%p, cidx=%d, bidx=%d", i, c->h, c->cidx, c->bidx);
 
32892
                }
 
32893
#endif
 
32894
        }
 
32895
 
 
32896
        return byte_offset;
 
32897
 
 
32898
 error:
 
32899
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "string scan error");
 
32900
        return 0;
 
32901
}
 
32902
 
 
32903
 
 
32904
#line 1 "duk_heap_stringtable.c"
 
32905
/*
 
32906
 *  Heap stringtable handling, string interning.
 
32907
 */
 
32908
 
 
32909
/* include removed: duk_internal.h */
 
32910
 
 
32911
#define DUK__HASH_INITIAL(hash,h_size)        DUK_STRTAB_HASH_INITIAL((hash),(h_size))
 
32912
#define DUK__HASH_PROBE_STEP(hash)            DUK_STRTAB_HASH_PROBE_STEP((hash))
 
32913
#define DUK__DELETED_MARKER(heap)             DUK_STRTAB_DELETED_MARKER((heap))
 
32914
 
 
32915
/*
 
32916
 *  Create a hstring and insert into the heap.  The created object
 
32917
 *  is directly garbage collectable with reference count zero.
 
32918
 *
 
32919
 *  The caller must place the interned string into the stringtable
 
32920
 *  immediately (without chance of a longjmp); otherwise the string
 
32921
 *  is lost.
 
32922
 */
 
32923
 
 
32924
static duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
 
32925
                                            duk_uint8_t *str,
 
32926
                                            duk_uint32_t blen,
 
32927
                                            duk_uint32_t strhash) {
 
32928
        duk_hstring *res = NULL;
 
32929
        duk_uint8_t *data;
 
32930
        duk_uint32_t alloc_size;
 
32931
        duk_uint32_t dummy;
 
32932
 
 
32933
        /* NUL terminate for convenient C access */
 
32934
 
 
32935
        alloc_size = sizeof(duk_hstring) + blen + 1;
 
32936
        res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
 
32937
        if (!res) {
 
32938
                goto error;
 
32939
        }
 
32940
 
 
32941
        DUK_MEMZERO(res, sizeof(duk_hstring));
 
32942
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
32943
        DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
 
32944
#endif
 
32945
        DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
 
32946
 
 
32947
        if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
 
32948
                DUK_HSTRING_SET_ARRIDX(res);
 
32949
        }
 
32950
 
 
32951
        res->hash = strhash;
 
32952
        res->blen = blen;
 
32953
        res->clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);  /* clen <= blen */
 
32954
 
 
32955
        data = (duk_uint8_t *) (res + 1);
 
32956
        DUK_MEMCPY(data, str, blen);
 
32957
        data[blen] = (duk_uint8_t) 0;
 
32958
 
 
32959
        DUK_DDDPRINT("interned string, hash=0x%08x, blen=%d, clen=%d, arridx=%d",
 
32960
                     DUK_HSTRING_GET_HASH(res),
 
32961
                     DUK_HSTRING_GET_BYTELEN(res),
 
32962
                     DUK_HSTRING_GET_CHARLEN(res),
 
32963
                     DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0);
 
32964
 
 
32965
        return res;
 
32966
 
 
32967
 error:
 
32968
        DUK_FREE(heap, res);
 
32969
        return NULL;
 
32970
}
 
32971
 
 
32972
/*
 
32973
 *  Count actually used (non-NULL, non-DELETED) entries
 
32974
 */
 
32975
 
 
32976
static duk_int_t duk__count_used(duk_heap *heap) {
 
32977
        duk_int_t res = 0;
 
32978
        duk_uint_fast32_t i, n;
 
32979
 
 
32980
        n = (duk_uint_fast32_t) heap->st_size;
 
32981
        for (i = 0; i < n; i++) {
 
32982
                if (heap->st[i] != NULL && heap->st[i] != DUK__DELETED_MARKER(heap)) {
 
32983
                        res++;
 
32984
                }
 
32985
        }
 
32986
        return res;
 
32987
}
 
32988
 
 
32989
/*
 
32990
 *  Hashtable lookup and insert helpers
 
32991
 */
 
32992
 
 
32993
static void duk__insert_hstring(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
 
32994
        duk_uint32_t i;
 
32995
        duk_uint32_t step;
 
32996
 
 
32997
        DUK_ASSERT(size > 0);
 
32998
 
 
32999
        i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
 
33000
        step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h)); 
 
33001
        for (;;) {
 
33002
                duk_hstring *e;
 
33003
                
 
33004
                e = entries[i];
 
33005
                if (e == NULL) {
 
33006
                        DUK_DDDPRINT("insert hit (null): %d", i);
 
33007
                        entries[i] = h;
 
33008
                        (*p_used)++;
 
33009
                        break;
 
33010
                } else if (e == DUK__DELETED_MARKER(heap)) {
 
33011
                        /* st_used remains the same, DELETED is counted as used */
 
33012
                        DUK_DDDPRINT("insert hit (deleted): %d", i);
 
33013
                        entries[i] = h;
 
33014
                        break;
 
33015
                }
 
33016
                DUK_DDDPRINT("insert miss: %d", i);
 
33017
                i = (i + step) % size;
 
33018
 
 
33019
                /* looping should never happen */
 
33020
                DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
 
33021
        }
 
33022
}
 
33023
 
 
33024
static duk_hstring *duk__find_matching_string(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
 
33025
        duk_uint32_t i;
 
33026
        duk_uint32_t step;
 
33027
 
 
33028
        DUK_ASSERT(size > 0);
 
33029
 
 
33030
        i = DUK__HASH_INITIAL(strhash, size);
 
33031
        step = DUK__HASH_PROBE_STEP(strhash);
 
33032
        for (;;) {
 
33033
                duk_hstring *e;
 
33034
 
 
33035
                e = entries[i];
 
33036
                if (!e) {
 
33037
                        return NULL;
 
33038
                }
 
33039
                if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
 
33040
                        if (DUK_MEMCMP(str, DUK_HSTRING_GET_DATA(e), blen) == 0) {
 
33041
                                DUK_DDDPRINT("find matching hit: %d (step %d, size %d)", i, step, size);
 
33042
                                return e;
 
33043
                        }
 
33044
                }
 
33045
                DUK_DDDPRINT("find matching miss: %d (step %d, size %d)", i, step, size);
 
33046
                i = (i + step) % size;
 
33047
 
 
33048
                /* looping should never happen */
 
33049
                DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
 
33050
        }
 
33051
        DUK_UNREACHABLE();
 
33052
}
 
33053
 
 
33054
static void duk__remove_matching_hstring(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
 
33055
        duk_uint32_t i;
 
33056
        duk_uint32_t step;
 
33057
 
 
33058
        DUK_ASSERT(size > 0);
 
33059
 
 
33060
        i = DUK__HASH_INITIAL(h->hash, size);
 
33061
        step = DUK__HASH_PROBE_STEP(h->hash);
 
33062
        for (;;) {
 
33063
                duk_hstring *e;
 
33064
 
 
33065
                e = entries[i];
 
33066
                if (!e) {
 
33067
                        DUK_UNREACHABLE();
 
33068
                        break;
 
33069
                }
 
33070
                if (e == h) {
 
33071
                        /* st_used remains the same, DELETED is counted as used */
 
33072
                        DUK_DDDPRINT("free matching hit: %d", i);
 
33073
                        entries[i] = DUK__DELETED_MARKER(heap);
 
33074
                        break;
 
33075
                }
 
33076
 
 
33077
                DUK_DDDPRINT("free matching miss: %d", i);
 
33078
                i = (i + step) % size;
 
33079
 
 
33080
                /* looping should never happen */
 
33081
                DUK_ASSERT(i != DUK__HASH_INITIAL(h->hash, size));
 
33082
        }
 
33083
}
 
33084
 
 
33085
/*
 
33086
 *  Hash resizing and resizing policy
 
33087
 */
 
33088
 
 
33089
static int duk__resize_strtab_raw(duk_heap *heap, duk_uint32_t new_size) {
 
33090
#ifdef DUK_USE_MARK_AND_SWEEP
 
33091
        int prev_mark_and_sweep_base_flags;
 
33092
#endif
 
33093
#ifdef DUK_USE_DDEBUG
 
33094
        duk_uint32_t old_used = heap->st_used;
 
33095
#endif
 
33096
        duk_uint32_t old_size = heap->st_size;
 
33097
        duk_hstring **old_entries = heap->st;
 
33098
        duk_hstring **new_entries = NULL;
 
33099
        duk_uint32_t new_used = 0;
 
33100
        duk_uint32_t i;
 
33101
 
 
33102
#ifdef DUK_USE_DEBUG
 
33103
        DUK_DDDPRINT("attempt to resize stringtable: %d entries, %d bytes, %d used, %d%% load -> %d entries, %d bytes, %d used, %d%% load",
 
33104
                     (int) old_size, (int) (sizeof(duk_hstring *) * old_size), (int) old_used,
 
33105
                     (int) (((double) old_used) / ((double) old_size) * 100.0),
 
33106
                     (int) new_size, (int) (sizeof(duk_hstring *) * new_size), (int) duk__count_used(heap),
 
33107
                     (int) (((double) duk__count_used(heap)) / ((double) new_size) * 100.0));
 
33108
#endif
 
33109
 
 
33110
        DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used(heap));  /* required for rehash to succeed, equality not that useful */
 
33111
        DUK_ASSERT(old_entries);
 
33112
#ifdef DUK_USE_MARK_AND_SWEEP
 
33113
        DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
 
33114
#endif
 
33115
 
 
33116
        /*
 
33117
         *  The attempt to allocate may cause a GC.  Such a GC must not attempt to resize
 
33118
         *  the stringtable (though it can be swept); finalizer execution and object
 
33119
         *  compaction must also be postponed to avoid the pressure to add strings to the
 
33120
         *  string table.
 
33121
         */
 
33122
 
 
33123
#ifdef DUK_USE_MARK_AND_SWEEP
 
33124
        prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
 
33125
        heap->mark_and_sweep_base_flags |= \
 
33126
                DUK_MS_FLAG_NO_STRINGTABLE_RESIZE |  /* avoid recursive call here */
 
33127
                DUK_MS_FLAG_NO_FINALIZERS |          /* avoid pressure to add/remove strings */
 
33128
                DUK_MS_FLAG_NO_OBJECT_COMPACTION;    /* avoid array abandoning which interns strings */
 
33129
#endif
 
33130
 
 
33131
        new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
 
33132
 
 
33133
#ifdef DUK_USE_MARK_AND_SWEEP
 
33134
        heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
 
33135
#endif
 
33136
 
 
33137
        if (!new_entries) {
 
33138
                goto error;
 
33139
        }
 
33140
 
 
33141
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
33142
        for (i = 0; i < new_size; i++) {
 
33143
                new_entries[i] = NULL;
 
33144
        }
 
33145
#else
 
33146
        DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
 
33147
#endif
 
33148
 
 
33149
        /* Because new_size > duk__count_used(heap), guaranteed to work */
 
33150
        for (i = 0; i < old_size; i++) {
 
33151
                duk_hstring *e;
 
33152
 
 
33153
                e = old_entries[i];
 
33154
                if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
 
33155
                        continue;
 
33156
                }
 
33157
                /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
 
33158
                duk__insert_hstring(heap, new_entries, new_size, &new_used, e);
 
33159
        }
 
33160
 
 
33161
#ifdef DUK_USE_DEBUG
 
33162
        DUK_DDPRINT("resized stringtable: %d entries, %d bytes, %d used, %d%% load -> %d entries, %d bytes, %d used, %d%% load",
 
33163
                    (int) old_size, (int) (sizeof(duk_hstring *) * old_size), (int) old_used,
 
33164
                    (int) (((double) old_used) / ((double) old_size) * 100.0),
 
33165
                    (int) new_size, (int) (sizeof(duk_hstring *) * new_size), (int) new_used,
 
33166
                    (int) (((double) new_used) / ((double) new_size) * 100.0));
 
33167
#endif
 
33168
 
 
33169
        DUK_FREE(heap, heap->st);
 
33170
        heap->st = new_entries;
 
33171
        heap->st_size = new_size;
 
33172
        heap->st_used = new_used;  /* may be less, since DELETED entries are NULLed by rehash */
 
33173
 
 
33174
        return 0;  /* OK */
 
33175
 
 
33176
 error:
 
33177
        DUK_FREE(heap, new_entries);
 
33178
        return 1;  /* FAIL */
 
33179
}
 
33180
 
 
33181
static int duk__resize_strtab(duk_heap *heap) {
 
33182
        duk_uint32_t new_size;
 
33183
        int ret;
 
33184
 
 
33185
        new_size = (duk_uint32_t) duk__count_used(heap);
 
33186
        if (new_size >= 0x80000000U) {
 
33187
                new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
 
33188
        } else {
 
33189
                new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
 
33190
                new_size = duk_util_get_hash_prime(new_size);
 
33191
        }
 
33192
        DUK_ASSERT(new_size > 0);
 
33193
 
 
33194
        /* rehash even if old and new sizes are the same to get rid of
 
33195
         * DELETED entries.
 
33196
        */ 
 
33197
 
 
33198
        ret = duk__resize_strtab_raw(heap, new_size);
 
33199
 
 
33200
        return ret;
 
33201
}
 
33202
 
 
33203
static int duk__recheck_strtab_size(duk_heap *heap, duk_uint32_t new_used) {
 
33204
        duk_uint32_t new_free;
 
33205
        duk_uint32_t tmp1;
 
33206
        duk_uint32_t tmp2;
 
33207
 
 
33208
        DUK_ASSERT(new_used <= heap->st_size);  /* grow by at most one */
 
33209
        new_free = heap->st_size - new_used;    /* unsigned intentionally */
 
33210
 
 
33211
        /* new_free / size <= 1 / DIV  <=>  new_free <= size / DIV */
 
33212
        /* new_used / size <= 1 / DIV  <=>  new_used <= size / DIV */
 
33213
 
 
33214
        tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
 
33215
        tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
 
33216
 
 
33217
        if (new_free <= tmp1 || new_used <= tmp2) {
 
33218
                /* load factor too low or high, count actually used entries and resize */
 
33219
                return duk__resize_strtab(heap);
 
33220
        } else {
 
33221
                return 0;  /* OK */
 
33222
        }
 
33223
}
 
33224
 
 
33225
/*
 
33226
 *  Raw intern and lookup
 
33227
 */
 
33228
 
 
33229
static duk_hstring *duk__do_intern(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
 
33230
        duk_hstring *res;
 
33231
 
 
33232
        if (duk__recheck_strtab_size(heap, heap->st_used + 1)) {
 
33233
                return NULL;
 
33234
        }
 
33235
 
 
33236
        res = duk__alloc_init_hstring(heap, str, blen, strhash);
 
33237
        if (!res) {
 
33238
                return NULL;
 
33239
        }
 
33240
 
 
33241
        duk__insert_hstring(heap, heap->st, heap->st_size, &heap->st_used, res);  /* guaranteed to succeed */
 
33242
 
 
33243
        /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
 
33244
         * Caller should increase refcount and make the hstring reachable before any
 
33245
         * operations which require allocation (and possible gc).
 
33246
         */
 
33247
 
 
33248
        return res;
 
33249
}
 
33250
 
 
33251
static duk_hstring *duk__do_lookup(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
 
33252
        duk_hstring *res;
 
33253
 
 
33254
        DUK_ASSERT(out_strhash);
 
33255
 
 
33256
        *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);  /* FIXME: change blen to duk_size_t */
 
33257
        res = duk__find_matching_string(heap, heap->st, heap->st_size, str, blen, *out_strhash);
 
33258
        return res;
 
33259
}
 
33260
 
 
33261
/*
 
33262
 *  Exposed calls
 
33263
 */
 
33264
 
 
33265
duk_hstring *duk_heap_string_lookup(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen) {
 
33266
        duk_uint32_t strhash;  /* dummy */
 
33267
        return duk__do_lookup(heap, str, blen, &strhash);
 
33268
}
 
33269
 
 
33270
duk_hstring *duk_heap_string_intern(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen) {
 
33271
        duk_hstring *res;
 
33272
        duk_uint32_t strhash;
 
33273
 
 
33274
        /* caller is responsible for ensuring this */
 
33275
        DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
 
33276
 
 
33277
        res = duk__do_lookup(heap, str, blen, &strhash);
 
33278
        if (res) {
 
33279
                return res;
 
33280
        }
 
33281
 
 
33282
        res = duk__do_intern(heap, str, blen, strhash);
 
33283
        return res;  /* may be NULL */
 
33284
}
 
33285
 
 
33286
duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, duk_uint8_t *str, duk_uint32_t blen) {
 
33287
        duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
 
33288
        if (!res) {
 
33289
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to intern string");
 
33290
        }
 
33291
        return res;
 
33292
}
 
33293
 
 
33294
duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
 
33295
        char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
 
33296
        DUK_SNPRINTF(buf, sizeof(buf), "%u", (unsigned int) val);
 
33297
        buf[sizeof(buf) - 1] = (char) 0;
 
33298
        return duk_heap_string_lookup(heap, (duk_uint8_t *) buf, DUK_STRLEN(buf));
 
33299
}
 
33300
 
 
33301
duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
 
33302
        char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
 
33303
        DUK_SNPRINTF(buf, sizeof(buf), "%u", (unsigned int) val);
 
33304
        buf[sizeof(buf) - 1] = (char) 0;
 
33305
        return duk_heap_string_intern(heap, (duk_uint8_t *) buf, DUK_STRLEN(buf));
 
33306
}
 
33307
 
 
33308
duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
 
33309
        duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
 
33310
        if (!res) {
 
33311
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to intern string");
 
33312
        }
 
33313
        return res;
 
33314
}
 
33315
 
 
33316
/* find and remove string from stringtable; caller must free the string itself */
 
33317
void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
 
33318
        DUK_DDDPRINT("remove string from stringtable: %!O", h);
 
33319
        duk__remove_matching_hstring(heap, heap->st, heap->st_size, h);
 
33320
}
 
33321
 
 
33322
#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
 
33323
void duk_heap_force_stringtable_resize(duk_heap *heap) {
 
33324
        /* Force a resize so that DELETED entries are eliminated.
 
33325
         * Another option would be duk__recheck_strtab_size(); but since
 
33326
         * that happens on every intern anyway, this whole check
 
33327
         * can now be disabled.
 
33328
         */
 
33329
        duk__resize_strtab(heap);
 
33330
}
 
33331
#endif
 
33332
 
 
33333
/* Undefine local defines */
 
33334
#undef DUK__HASH_INITIAL
 
33335
#undef DUK__HASH_PROBE_STEP
 
33336
#undef DUK__DELETED_MARKER
 
33337
 
 
33338
#line 1 "duk_hobject_alloc.c"
 
33339
/*
 
33340
 *  Hobject allocation.
 
33341
 *
 
33342
 *  Provides primitive allocation functions for all object types (plain object,
 
33343
 *  compiled function, native function, thread).  The object return is not yet
 
33344
 *  in "heap allocated" list and has a refcount of zero, so caller must careful.
 
33345
 */
 
33346
 
 
33347
/* include removed: duk_internal.h */
 
33348
 
 
33349
static void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, int hobject_flags) {
 
33350
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
33351
        obj->p = NULL;
 
33352
#endif
 
33353
 
 
33354
        /* FIXME: macro? sets both heaphdr and object flags */
 
33355
        obj->hdr.h_flags = hobject_flags;
 
33356
        DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT);  /* also goes into flags */
 
33357
 
 
33358
        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
 
33359
 
 
33360
        /*
 
33361
         *  obj->p is intentionally left as NULL, and duk_hobject_props.c must deal
 
33362
         *  with this properly.  This is intentional: empty objects consume a minimum
 
33363
         *  amount of memory.  Further, an initial allocation might fail and cause
 
33364
         *  'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
 
33365
         */
 
33366
}
 
33367
 
 
33368
/*
 
33369
 *  Allocate an duk_hobject.
 
33370
 *
 
33371
 *  The allocated object has no allocation for properties; the caller may
 
33372
 *  want to force a resize if a desired size is known.
 
33373
 *
 
33374
 *  The allocated object has zero reference count and is not reachable.
 
33375
 *  The caller MUST make the object reachable and increase its reference
 
33376
 *  count before invoking any operation that might require memory allocation.
 
33377
 */
 
33378
 
 
33379
duk_hobject *duk_hobject_alloc(duk_heap *heap, int hobject_flags) {
 
33380
        duk_hobject *res;
 
33381
 
 
33382
        DUK_ASSERT(heap != NULL);
 
33383
 
 
33384
        /* different memory layout, alloc size, and init */
 
33385
        DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
 
33386
        DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
 
33387
        DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
 
33388
 
 
33389
        res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
 
33390
        if (!res) {
 
33391
                return NULL;
 
33392
        }
 
33393
        DUK_MEMZERO(res, sizeof(duk_hobject));
 
33394
 
 
33395
        duk__init_object_parts(heap, res, hobject_flags);
 
33396
 
 
33397
        return res;
 
33398
}
 
33399
 
 
33400
duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, int hobject_flags) {
 
33401
        duk_hcompiledfunction *res;
 
33402
 
 
33403
        res = (duk_hcompiledfunction *) DUK_ALLOC(heap, sizeof(duk_hcompiledfunction));
 
33404
        if (!res) {
 
33405
                return NULL;
 
33406
        }
 
33407
        DUK_MEMZERO(res, sizeof(duk_hcompiledfunction));
 
33408
 
 
33409
        duk__init_object_parts(heap, &res->obj, hobject_flags);
 
33410
 
 
33411
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
33412
        res->data = NULL;
 
33413
        res->funcs = NULL;
 
33414
        res->bytecode = NULL;
 
33415
#endif
 
33416
 
 
33417
        return res;
 
33418
}
 
33419
 
 
33420
duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, int hobject_flags) {
 
33421
        duk_hnativefunction *res;
 
33422
 
 
33423
        res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
 
33424
        if (!res) {
 
33425
                return NULL;
 
33426
        }
 
33427
        DUK_MEMZERO(res, sizeof(duk_hnativefunction));
 
33428
 
 
33429
        duk__init_object_parts(heap, &res->obj, hobject_flags);
 
33430
 
 
33431
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
33432
        res->func = NULL;
 
33433
#endif
 
33434
 
 
33435
        return res;
 
33436
}
 
33437
 
 
33438
/*
 
33439
 *  Allocate a new thread.
 
33440
 *
 
33441
 *  Leaves the built-ins array uninitialized.  The caller must either
 
33442
 *  initialize a new global context or share existing built-ins from
 
33443
 *  another thread.
 
33444
 */
 
33445
 
 
33446
duk_hthread *duk_hthread_alloc(duk_heap *heap, int hobject_flags) {
 
33447
        duk_hthread *res;
 
33448
 
 
33449
        res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
 
33450
        if (!res) {
 
33451
                return NULL;
 
33452
        }
 
33453
        DUK_MEMZERO(res, sizeof(duk_hthread));
 
33454
 
 
33455
        duk__init_object_parts(heap, &res->obj, hobject_flags);
 
33456
 
 
33457
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
33458
        res->heap = NULL;
 
33459
        res->valstack = NULL;
 
33460
        res->valstack_end = NULL;
 
33461
        res->valstack_bottom = NULL;
 
33462
        res->valstack_top = NULL;
 
33463
        res->callstack = NULL;
 
33464
        res->catchstack = NULL;
 
33465
        res->resumer = NULL;
 
33466
        res->strs = NULL;
 
33467
        {
 
33468
                int i;
 
33469
                for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
33470
                        res->builtins[i] = NULL;
 
33471
                }
 
33472
        }
 
33473
#endif
 
33474
        /* when nothing is running, API calls are in non-strict mode */
 
33475
        DUK_ASSERT(res->strict == 0);
 
33476
 
 
33477
        res->heap = heap;
 
33478
        res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
 
33479
        res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
 
33480
        res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
 
33481
 
 
33482
        return res;
 
33483
}
 
33484
 
 
33485
/* FIXME: unused now, remove */
 
33486
duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, int hobject_flags) {
 
33487
        duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
 
33488
        if (!res) {
 
33489
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate an object");
 
33490
        }
 
33491
        return res;
 
33492
}
 
33493
#line 1 "duk_hobject_class.c"
 
33494
/*
 
33495
 *  Hobject Ecmascript [[Class]].
 
33496
 */
 
33497
 
 
33498
/* include removed: duk_internal.h */
 
33499
 
 
33500
/* Maybe better to check these elsewhere */
 
33501
#if (DUK_STRIDX_UC_ARGUMENTS > 255)
 
33502
#error constant too large
 
33503
#endif
 
33504
#if (DUK_STRIDX_ARRAY > 255)
 
33505
#error constant too large
 
33506
#endif
 
33507
#if (DUK_STRIDX_UC_BOOLEAN > 255)
 
33508
#error constant too large
 
33509
#endif
 
33510
#if (DUK_STRIDX_DATE > 255)
 
33511
#error constant too large
 
33512
#endif
 
33513
#if (DUK_STRIDX_UC_ERROR > 255)
 
33514
#error constant too large
 
33515
#endif
 
33516
#if (DUK_STRIDX_UC_FUNCTION > 255)
 
33517
#error constant too large
 
33518
#endif
 
33519
#if (DUK_STRIDX_JSON > 255)
 
33520
#error constant too large
 
33521
#endif
 
33522
#if (DUK_STRIDX_MATH > 255)
 
33523
#error constant too large
 
33524
#endif
 
33525
#if (DUK_STRIDX_UC_NUMBER > 255)
 
33526
#error constant too large
 
33527
#endif
 
33528
#if (DUK_STRIDX_UC_OBJECT > 255)
 
33529
#error constant too large
 
33530
#endif
 
33531
#if (DUK_STRIDX_REG_EXP > 255)
 
33532
#error constant too large
 
33533
#endif
 
33534
#if (DUK_STRIDX_UC_STRING > 255)
 
33535
#error constant too large
 
33536
#endif
 
33537
#if (DUK_STRIDX_GLOBAL > 255)
 
33538
#error constant too large
 
33539
#endif
 
33540
#if (DUK_STRIDX_EMPTY_STRING > 255)
 
33541
#error constant too large
 
33542
#endif
 
33543
 
 
33544
/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
 
33545
duk_uint8_t duk_class_number_to_stridx[32] = {
 
33546
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33547
        DUK_STRIDX_UC_ARGUMENTS,
 
33548
        DUK_STRIDX_ARRAY,
 
33549
        DUK_STRIDX_UC_BOOLEAN,
 
33550
        DUK_STRIDX_DATE,
 
33551
        DUK_STRIDX_UC_ERROR,
 
33552
        DUK_STRIDX_UC_FUNCTION,
 
33553
        DUK_STRIDX_JSON,
 
33554
        DUK_STRIDX_MATH,
 
33555
        DUK_STRIDX_UC_NUMBER,
 
33556
        DUK_STRIDX_UC_OBJECT,
 
33557
        DUK_STRIDX_REG_EXP,
 
33558
        DUK_STRIDX_UC_STRING,
 
33559
        DUK_STRIDX_GLOBAL,
 
33560
        DUK_STRIDX_OBJ_ENV,
 
33561
        DUK_STRIDX_DEC_ENV,
 
33562
        DUK_STRIDX_UC_BUFFER,
 
33563
        DUK_STRIDX_UC_POINTER,
 
33564
        DUK_STRIDX_UC_THREAD,     /* UNUSED, intentionally empty */
 
33565
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33566
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33567
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33568
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33569
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33570
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33571
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33572
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33573
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33574
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33575
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33576
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33577
        DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
 
33578
};
 
33579
 
 
33580
#line 1 "duk_hobject_enum.c"
 
33581
/*
 
33582
 *  Hobject enumeration support.
 
33583
 *
 
33584
 *  Creates an internal enumeration state object to be used e.g. with for-in
 
33585
 *  enumeration.  The state object contains a snapshot of target object keys
 
33586
 *  and internal control state for enumeration.  Enumerator flags allow caller
 
33587
 *  to e.g. request internal/non-enumerable properties, and to enumerate only
 
33588
 *  "own" properties.
 
33589
 *
 
33590
 *  Also creates the result value for e.g. Object.keys() based on the same
 
33591
 *  internal structure.
 
33592
 *
 
33593
 *  This snapshot-based enumeration approach is used to simplify enumeration:
 
33594
 *  non-snapshot-based approaches are difficult to reconcile with mutating
 
33595
 *  the enumeration target, running multiple long-lived enumerators at the
 
33596
 *  same time, garbage collection details, etc.  The downside is that the
 
33597
 *  enumerator object is memory inefficient especially for iterating arrays.
 
33598
 */
 
33599
 
 
33600
/* include removed: duk_internal.h */
 
33601
 
 
33602
/* FIXME: identify enumeration target with an object index (not top of stack) */
 
33603
 
 
33604
/* must match exactly the number of internal properties inserted to enumerator */
 
33605
#define DUK__ENUM_START_INDEX  2
 
33606
 
 
33607
/*
 
33608
 *  Helper to sort array index keys.  The keys are in the enumeration object
 
33609
 *  entry part, starting from DUK__ENUM_START_INDEX, and the entry part is dense.
 
33610
 *
 
33611
 *  We use insertion sort because it is simple (leading to compact code,)
 
33612
 *  works nicely in-place, and minimizes operations if data is already sorted
 
33613
 *  or nearly sorted (which is a very common case here).  It also minimizes
 
33614
 *  the use of element comparisons in general.  This is nice because element
 
33615
 *  comparisons here involve re-parsing the string keys into numbers each
 
33616
 *  time, which is naturally very expensive.
 
33617
 *
 
33618
 *  Note that the entry part values are all "true", e.g.
 
33619
 *
 
33620
 *    "1" -> true, "3" -> true, "2" -> true
 
33621
 *
 
33622
 *  so it suffices to only work in the key part without exchanging any keys,
 
33623
 *  simplifying the sort.
 
33624
 *
 
33625
 *  http://en.wikipedia.org/wiki/Insertion_sort
 
33626
 *
 
33627
 *  (Compiles to about 160 bytes now as a stand-alone function.)
 
33628
 */
 
33629
 
 
33630
static void duk__sort_array_indices(duk_hobject *h_obj) {
 
33631
        duk_hstring **keys;
 
33632
        duk_hstring **p_curr, **p_insert, **p_end;
 
33633
        duk_hstring *h_curr;
 
33634
        duk_uint32_t val_highest, val_curr, val_insert;
 
33635
 
 
33636
        DUK_ASSERT(h_obj != NULL);
 
33637
        DUK_ASSERT(h_obj->e_used >= 2);  /* control props */
 
33638
 
 
33639
        if (h_obj->e_used <= 1 + DUK__ENUM_START_INDEX) {
 
33640
                return;
 
33641
        }
 
33642
 
 
33643
        keys = DUK_HOBJECT_E_GET_KEY_BASE(h_obj);
 
33644
        p_end = keys + h_obj->e_used;
 
33645
        keys += DUK__ENUM_START_INDEX;
 
33646
 
 
33647
        DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
 
33648
                     (void *) keys, (void *) p_end);
 
33649
 
 
33650
#ifdef DUK_USE_DDDEBUG
 
33651
        {
 
33652
                duk_uint_fast32_t i;
 
33653
                for (i = 0; i < (duk_uint_fast32_t) h_obj->e_used; i++) {
 
33654
                        DUK_DDDPRINT("initial: %d %p -> %!O",
 
33655
                                     (int) i,
 
33656
                                     (void *) DUK_HOBJECT_E_GET_KEY_PTR(h_obj, i),
 
33657
                                     (void *) DUK_HOBJECT_E_GET_KEY(h_obj, i));
 
33658
                }
 
33659
        }
 
33660
#endif
 
33661
 
 
33662
        val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
 
33663
        for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
 
33664
                DUK_ASSERT(*p_curr != NULL);
 
33665
                val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
 
33666
 
 
33667
                if (val_curr >= val_highest) {
 
33668
                        DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%d, val_curr=%d -> "
 
33669
                                     "already in correct order, next",
 
33670
                                     (void *) p_curr, (void *) p_end, (int) val_highest, (int) val_curr);
 
33671
                        val_highest = val_curr;
 
33672
                        continue;
 
33673
                }
 
33674
 
 
33675
                DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%d, val_curr=%d -> "
 
33676
                             "needs to be inserted",
 
33677
                             (void *) p_curr, (void *) p_end, (int) val_highest, (int) val_curr);
 
33678
        
 
33679
                /* Needs to be inserted; scan backwards, since we optimize
 
33680
                 * for the case where elements are nearly in order.
 
33681
                 */
 
33682
 
 
33683
                p_insert = p_curr - 1;
 
33684
                for (;;) {
 
33685
                        val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
 
33686
                        if (val_insert < val_curr) {
 
33687
                                DUK_DDDPRINT("p_insert=%p, val_insert=%d, val_curr=%d -> insert after this",
 
33688
                                             (void *) p_insert, (int) val_insert, (int) val_curr);
 
33689
                                p_insert++;
 
33690
                                break;
 
33691
                        }
 
33692
                        if (p_insert == keys) {
 
33693
                                DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning");
 
33694
                                break;
 
33695
                        }
 
33696
                        DUK_DDDPRINT("p_insert=%p, val_insert=%d, val_curr=%d -> search backwards",
 
33697
                                     (void *) p_insert, (int) val_insert, (int) val_curr);
 
33698
                        p_insert--;
 
33699
                }
 
33700
 
 
33701
                DUK_DDDPRINT("final p_insert=%p", (void *) p_insert);
 
33702
 
 
33703
                /*        .-- p_insert   .-- p_curr
 
33704
                 *        v              v
 
33705
                 *  | ... | insert | ... | curr
 
33706
                 */
 
33707
 
 
33708
                h_curr = *p_curr;
 
33709
                DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%d, h_curr=%p",
 
33710
                             (void *) (p_insert + 1), (void *) p_insert,
 
33711
                             (int) (p_curr - p_insert), (void *) h_curr);
 
33712
 
 
33713
                DUK_MEMMOVE((void *) (p_insert + 1),
 
33714
                            (void *) p_insert,
 
33715
                            (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
 
33716
                *p_insert = h_curr;
 
33717
                /* keep val_highest */
 
33718
        }
 
33719
 
 
33720
#ifdef DUK_USE_DDDEBUG
 
33721
        {
 
33722
                duk_uint_fast32_t i;
 
33723
                for (i = 0; i < (duk_uint_fast32_t) h_obj->e_used; i++) {
 
33724
                        DUK_DDDPRINT("final: %d %p -> %!O",
 
33725
                                     (int) i,
 
33726
                                     (void *) DUK_HOBJECT_E_GET_KEY_PTR(h_obj, i),
 
33727
                                     (void *) DUK_HOBJECT_E_GET_KEY(h_obj, i));
 
33728
                }
 
33729
        }
 
33730
#endif
 
33731
}
 
33732
 
 
33733
/*
 
33734
 *  Create an internal enumerator object E, which has its keys ordered
 
33735
 *  to match desired enumeration ordering.  Also initialize internal control
 
33736
 *  properties for enumeration.
 
33737
 *
 
33738
 *  Note: if an array was used to hold enumeration keys instead, an array
 
33739
 *  scan would be needed to eliminate duplicates found in the prototype chain.
 
33740
 */
 
33741
 
 
33742
void duk_hobject_enumerator_create(duk_context *ctx, int enum_flags) {
 
33743
        duk_hthread *thr = (duk_hthread *) ctx;
 
33744
        duk_hobject *target;
 
33745
        duk_hobject *curr;
 
33746
        duk_hobject *res;
 
33747
 
 
33748
        DUK_ASSERT(ctx != NULL);
 
33749
 
 
33750
        DUK_DDDPRINT("create enumerator, stack top: %d", duk_get_top(ctx));
 
33751
 
 
33752
        target = duk_require_hobject(ctx, -1);
 
33753
        DUK_ASSERT(target != NULL);
 
33754
 
 
33755
        duk_push_object_internal(ctx);
 
33756
 
 
33757
        DUK_DDDPRINT("created internal object");
 
33758
 
 
33759
        /* [target res] */
 
33760
 
 
33761
        duk_push_hstring_stridx(ctx, DUK_STRIDX_INT_TARGET);
 
33762
        duk_push_hobject(ctx, target);
 
33763
        duk_put_prop(ctx, -3);
 
33764
 
 
33765
        /* initialize index so that we skip internal control keys */
 
33766
        duk_push_hstring_stridx(ctx, DUK_STRIDX_INT_NEXT);
 
33767
        duk_push_int(ctx, DUK__ENUM_START_INDEX);
 
33768
        duk_put_prop(ctx, -3);
 
33769
 
 
33770
        curr = target;
 
33771
        while (curr) {
 
33772
                duk_uint32_t i, len;
 
33773
 
 
33774
                /*
 
33775
                 *  Virtual properties.
 
33776
                 *
 
33777
                 *  String and buffer indices are virtual and always enumerable,
 
33778
                 *  'length' is virtual and non-enumerable.  Array and arguments
 
33779
                 *  object props have special behavior but are concrete.
 
33780
                 */
 
33781
 
 
33782
                if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(curr) ||
 
33783
                    DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr)) {
 
33784
                        /* String and buffer enumeration behavior is identical now,
 
33785
                         * so use shared handler.
 
33786
                         */
 
33787
                        if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(curr)) {
 
33788
                                duk_hstring *h_val;
 
33789
                                h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
 
33790
                                DUK_ASSERT(h_val != NULL);  /* string objects must not created without internal value */
 
33791
                                len = DUK_HSTRING_GET_CHARLEN(h_val);
 
33792
                        } else {
 
33793
                                duk_hbuffer *h_val;
 
33794
                                DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr));
 
33795
                                h_val = duk_hobject_get_internal_value_buffer(thr->heap, curr);
 
33796
                                DUK_ASSERT(h_val != NULL);  /* buffer objects must not created without internal value */
 
33797
                                len = DUK_HBUFFER_GET_SIZE(h_val);
 
33798
                        }
 
33799
 
 
33800
                        /* FIXME: type for 'i' to match string max len (duk_uint32_t) */
 
33801
                        for (i = 0; i < len; i++) {
 
33802
                                duk_hstring *k;
 
33803
 
 
33804
                                k = duk_heap_string_intern_u32_checked(thr, i);
 
33805
                                DUK_ASSERT(k);
 
33806
                                duk_push_hstring(ctx, k);
 
33807
                                duk_push_true(ctx);
 
33808
 
 
33809
                                /* [target res key true] */
 
33810
                                duk_put_prop(ctx, -3);
 
33811
 
 
33812
                                /* [target res] */      
 
33813
                        }
 
33814
 
 
33815
                        /* 'length' property is not enumerable, but is included if
 
33816
                         * non-enumerable properties are requested.
 
33817
                         */
 
33818
 
 
33819
                        if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
 
33820
                                duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
 
33821
                                duk_push_true(ctx);
 
33822
                                duk_put_prop(ctx, -3);
 
33823
                        }
 
33824
                } else if (DUK_HOBJECT_HAS_SPECIAL_DUKFUNC(curr)) {
 
33825
                        if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
 
33826
                                duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
 
33827
                                duk_push_true(ctx);
 
33828
                                duk_put_prop(ctx, -3);
 
33829
                        }
 
33830
                }
 
33831
 
 
33832
                /*
 
33833
                 *  Array part
 
33834
                 *
 
33835
                 *  Note: ordering between array and entry part must match 'abandon array'
 
33836
                 *  behavior in duk_hobject_props.c: key order after an array is abandoned
 
33837
                 *  must be the same.
 
33838
                 */
 
33839
 
 
33840
                for (i = 0; i < curr->a_size; i++) {
 
33841
                        duk_hstring *k;
 
33842
                        duk_tval *tv;
 
33843
 
 
33844
                        tv = DUK_HOBJECT_A_GET_VALUE_PTR(curr, i);
 
33845
                        if (DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
33846
                                continue;
 
33847
                        }
 
33848
                        k = duk_heap_string_intern_u32_checked(thr, i);
 
33849
                        DUK_ASSERT(k);
 
33850
 
 
33851
                        duk_push_hstring(ctx, k);
 
33852
                        duk_push_true(ctx);
 
33853
 
 
33854
                        /* [target res key true] */
 
33855
                        duk_put_prop(ctx, -3);
 
33856
 
 
33857
                        /* [target res] */
 
33858
                }
 
33859
 
 
33860
                /*
 
33861
                 *  Entries part
 
33862
                 */
 
33863
 
 
33864
                for (i = 0; i < curr->e_used; i++) {
 
33865
                        duk_hstring *k;
 
33866
 
 
33867
                        k = DUK_HOBJECT_E_GET_KEY(curr, i);
 
33868
                        if (!k) {
 
33869
                                continue;
 
33870
                        }
 
33871
                        if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(curr, i) &&
 
33872
                            !(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
 
33873
                                continue;
 
33874
                        }
 
33875
                        if (DUK_HSTRING_HAS_INTERNAL(k) &&
 
33876
                            !(enum_flags & DUK_ENUM_INCLUDE_INTERNAL)) {
 
33877
                                continue;
 
33878
                        }
 
33879
                        if ((enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) &&
 
33880
                            (DUK_HSTRING_GET_ARRIDX_SLOW(k) == DUK_HSTRING_NO_ARRAY_INDEX)) {
 
33881
                                continue;
 
33882
                        }
 
33883
 
 
33884
                        DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(curr, i) ||
 
33885
                                   !DUK_TVAL_IS_UNDEFINED_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(curr, i)->v));
 
33886
 
 
33887
                        duk_push_hstring(ctx, k);
 
33888
                        duk_push_true(ctx);
 
33889
 
 
33890
                        /* [target res key true] */
 
33891
                        duk_put_prop(ctx, -3);
 
33892
 
 
33893
                        /* [target res] */
 
33894
                }
 
33895
 
 
33896
                if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
 
33897
                        break;
 
33898
                }
 
33899
 
 
33900
                curr = curr->prototype;
 
33901
        }
 
33902
 
 
33903
        /* [target res] */
 
33904
 
 
33905
        duk_remove(ctx, -2);
 
33906
        res = duk_require_hobject(ctx, -1);
 
33907
 
 
33908
        /* [res] */
 
33909
 
 
33910
        if ((enum_flags & (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) ==
 
33911
                          (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) {
 
33912
                /*
 
33913
                 *  Some E5/E5.1 algorithms require that array indices are iterated
 
33914
                 *  in a strictly ascending order.  This is the case for e.g.
 
33915
                 *  Array.prototype.forEach() and JSON.stringify() PropertyList
 
33916
                 *  handling.
 
33917
                 *
 
33918
                 *  To ensure this property for arrays with an array part (and
 
33919
                 *  arbitrary objects too, since e.g. forEach() can be applied
 
33920
                 *  to an array), the caller can request that we sort the keys
 
33921
                 *  here.
 
33922
                 */
 
33923
 
 
33924
                /* FIXME: avoid this at least when target is an Array, it has an
 
33925
                 * array part, and no ancestor properties were included?  Not worth
 
33926
                 * it for JSON, but maybe worth it for forEach().
 
33927
                 */
 
33928
 
 
33929
                /* FIXME: may need a 'length' filter for forEach()
 
33930
                 */
 
33931
                DUK_DDDPRINT("sort array indices by caller request");
 
33932
                duk__sort_array_indices(res);
 
33933
        }
 
33934
 
 
33935
        /* compact; no need to seal because object is internal */
 
33936
        duk_hobject_compact_props(thr, res);
 
33937
 
 
33938
        DUK_DDDPRINT("created enumerator object: %!iT", duk_get_tval(ctx, -1));
 
33939
}
 
33940
 
 
33941
/*
 
33942
 *  Returns non-zero if a key and/or value was enumerated, and:
 
33943
 *
 
33944
 *   [enum] -> [key]        (get_value == 0)
 
33945
 *   [enum] -> [key value]  (get_value == 1)
 
33946
 *
 
33947
 *  Returns zero without pushing anything on the stack otherwise.
 
33948
 */
 
33949
int duk_hobject_enumerator_next(duk_context *ctx, int get_value) {
 
33950
        duk_hthread *thr = (duk_hthread *) ctx;
 
33951
        duk_hobject *e;
 
33952
        duk_hobject *target;
 
33953
        duk_hstring *res = NULL;
 
33954
        duk_uint32_t idx;
 
33955
 
 
33956
        DUK_ASSERT(ctx != NULL);
 
33957
 
 
33958
        /* [... enum] */
 
33959
 
 
33960
        e = duk_require_hobject(ctx, -1);
 
33961
 
 
33962
        /* FIXME: use get tval ptr, more efficient */
 
33963
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_NEXT);
 
33964
        idx = (duk_uint32_t) duk_require_number(ctx, -1);
 
33965
        duk_pop(ctx);
 
33966
        DUK_DDDPRINT("enumeration: index is: %d", idx);
 
33967
 
 
33968
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
 
33969
        target = duk_require_hobject(ctx, -1);
 
33970
        DUK_ASSERT(target != NULL);
 
33971
        duk_pop(ctx);  /* still reachable */
 
33972
 
 
33973
        DUK_DDDPRINT("getting next enum value, target=%!iO, enumerator=%!iT",
 
33974
                     target, duk_get_tval(ctx, -1));
 
33975
 
 
33976
        /* no array part */
 
33977
        for (;;) {
 
33978
                duk_hstring *k;
 
33979
 
 
33980
                if (idx >= e->e_used) {
 
33981
                        DUK_DDDPRINT("enumeration: ran out of elements");
 
33982
                        break;
 
33983
                }
 
33984
 
 
33985
                /* we know these because enum objects are internally created */
 
33986
                k = DUK_HOBJECT_E_GET_KEY(e, idx);
 
33987
                DUK_ASSERT(k != NULL);
 
33988
                DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(e, idx));
 
33989
                DUK_ASSERT(!DUK_TVAL_IS_UNDEFINED_UNUSED(&DUK_HOBJECT_E_GET_VALUE(e, idx).v));
 
33990
 
 
33991
                idx++;
 
33992
 
 
33993
                /* recheck that the property still exists */
 
33994
                if (!duk_hobject_hasprop_raw(thr, target, k)) {
 
33995
                        DUK_DDDPRINT("property deleted during enumeration, skip");
 
33996
                        continue;
 
33997
                }
 
33998
 
 
33999
                DUK_DDDPRINT("enumeration: found element, key: %!O", k);
 
34000
                res = k;
 
34001
                break;
 
34002
        }
 
34003
 
 
34004
        DUK_DDDPRINT("enumeration: updating next index to %d", idx);
 
34005
 
 
34006
        duk_push_number(ctx, (double) idx);
 
34007
        duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
 
34008
 
 
34009
        /* [... enum] */
 
34010
 
 
34011
        if (res) {
 
34012
                duk_push_hstring(ctx, res);
 
34013
                if (get_value) {
 
34014
                        duk_push_hobject(ctx, target);
 
34015
                        duk_dup(ctx, -2);      /* -> [... enum key target key] */
 
34016
                        duk_get_prop(ctx, -2); /* -> [... enum key target val] */
 
34017
                        duk_remove(ctx, -2);   /* -> [... enum key val] */
 
34018
                        duk_remove(ctx, -3);   /* -> [... key val] */
 
34019
                } else {
 
34020
                        duk_remove(ctx, -2);   /* -> [... key] */
 
34021
                }
 
34022
                return 1;
 
34023
        } else {
 
34024
                duk_pop(ctx);  /* -> [...] */
 
34025
                return 0;
 
34026
        }
 
34027
}
 
34028
 
 
34029
/*
 
34030
 *  Get enumerated keys in an Ecmascript array.  Matches Object.keys() behavior
 
34031
 *  described in E5 Section 15.2.3.14.
 
34032
 */
 
34033
 
 
34034
int duk_hobject_get_enumerated_keys(duk_context *ctx, int enum_flags) {
 
34035
        duk_hobject *e;
 
34036
        duk_uint32_t i;
 
34037
        duk_uint32_t idx;
 
34038
 
 
34039
        DUK_ASSERT(ctx != NULL);
 
34040
        DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
 
34041
 
 
34042
        /* Create a temporary enumerator to get the (non-duplicated) key list;
 
34043
         * the enumerator state is initialized without being needed, but that
 
34044
         * has little impact.
 
34045
         */
 
34046
 
 
34047
        duk_hobject_enumerator_create(ctx, enum_flags);
 
34048
        duk_push_array(ctx);
 
34049
 
 
34050
        /* [target enum res] */
 
34051
 
 
34052
        e = duk_require_hobject(ctx, -2);
 
34053
        DUK_ASSERT(e != NULL);
 
34054
 
 
34055
        idx = 0;
 
34056
        for (i = DUK__ENUM_START_INDEX; i < e->e_used; i++) {
 
34057
                duk_hstring *k;
 
34058
 
 
34059
                k = DUK_HOBJECT_E_GET_KEY(e, i);
 
34060
                DUK_ASSERT(k);  /* enumerator must have no keys deleted */
 
34061
 
 
34062
                /* [target enum res] */
 
34063
                duk_push_hstring(ctx, k);
 
34064
                duk_put_prop_index(ctx, -2, idx);
 
34065
                idx++;
 
34066
        }
 
34067
 
 
34068
        /* [target enum res] */
 
34069
        duk_remove(ctx, -2);
 
34070
 
 
34071
        /* [target res] */
 
34072
 
 
34073
        return 1;  /* return 1 to allow callers to tail call */
 
34074
}
 
34075
 
 
34076
#line 1 "duk_hobject_finalizer.c"
 
34077
/*
 
34078
 *  Run an duk_hobject finalizer.  Used for both reference counting
 
34079
 *  and mark-and-sweep algorithms.  Must never throw an error.
 
34080
 *
 
34081
 *  There is no return value.  Any return value or error thrown by
 
34082
 *  the finalizer is ignored (although errors are debug logged).
 
34083
 *
 
34084
 *  Notes:
 
34085
 *
 
34086
 *    - The thread used for calling the finalizer is the same as the
 
34087
 *      'thr' argument.  This may need to change later.
 
34088
 *
 
34089
 *    - The finalizer thread 'top' assertions are there because it is
 
34090
 *      critical that strict stack policy is observed (i.e. no cruft
 
34091
 *      left on the finalizer stack).
 
34092
 */
 
34093
 
 
34094
/* include removed: duk_internal.h */
 
34095
 
 
34096
static int duk__finalize_helper(duk_context *ctx) {
 
34097
        DUK_ASSERT(ctx != NULL);
 
34098
 
 
34099
        DUK_DDDPRINT("protected finalization helper running");
 
34100
 
 
34101
        /* [... obj] */
 
34102
 
 
34103
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER);  /* -> [... obj finalizer] */
 
34104
        if (!duk_is_callable(ctx, -1)) {
 
34105
                DUK_DDDPRINT("-> no finalizer or finalizer not callable");
 
34106
                return 0;
 
34107
        }
 
34108
        duk_dup(ctx, -2);  /* -> [... obj finalizer obj] */
 
34109
        DUK_DDDPRINT("-> finalizer found, calling finalizer");
 
34110
        duk_call(ctx, 1);  /* -> [... obj retval] */
 
34111
        DUK_DDDPRINT("finalizer finished successfully");
 
34112
        return 0;
 
34113
 
 
34114
        /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
 
34115
         * so we don't need to pop stuff here.  There is no return value;
 
34116
         * caller determines rescued status based on object refcount.
 
34117
         */
 
34118
}
 
34119
 
 
34120
void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
 
34121
        duk_context *ctx = (duk_context *) thr;
 
34122
        int rc;
 
34123
#ifdef DUK_USE_ASSERTIONS
 
34124
        int entry_top;
 
34125
#endif
 
34126
 
 
34127
        DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj);
 
34128
 
 
34129
        DUK_ASSERT(thr != NULL);
 
34130
        DUK_ASSERT(ctx != NULL);
 
34131
        DUK_ASSERT(obj != NULL);
 
34132
 
 
34133
        /* FIXME: assert stack space */
 
34134
 
 
34135
#ifdef DUK_USE_ASSERTIONS
 
34136
        entry_top = duk_get_top(ctx);
 
34137
#endif
 
34138
        /*
 
34139
         *  Get and call the finalizer.  All of this must be wrapped
 
34140
         *  in a protected call, because even getting the finalizer
 
34141
         *  may trigger an error (getter may throw one, for instance).
 
34142
         */
 
34143
 
 
34144
        /* FIXME: use a NULL error handler for the finalizer call? */
 
34145
 
 
34146
        DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper");
 
34147
        duk_push_hobject(ctx, obj);  /* this also increases refcount by one */
 
34148
        rc = duk_safe_call(ctx, duk__finalize_helper, 0 /*nargs*/, 1 /*nrets*/);  /* -> [... obj retval/error] */
 
34149
        DUK_ASSERT_TOP(ctx, entry_top + 2);  /* duk_safe_call discipline */
 
34150
 
 
34151
        if (rc != DUK_EXEC_SUCCESS) {
 
34152
                /* Note: we ask for one return value from duk_safe_call to get this
 
34153
                 * error debugging here.
 
34154
                 */
 
34155
                DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
 
34156
                           (void *) obj, duk_get_tval(ctx, -1));
 
34157
        }
 
34158
        duk_pop_2(ctx);  /* -> [...] */
 
34159
 
 
34160
        DUK_ASSERT_TOP(ctx, entry_top);
 
34161
}
 
34162
 
 
34163
#line 1 "duk_hobject_misc.c"
 
34164
/*
 
34165
 *  Misc support functions
 
34166
 */
 
34167
 
 
34168
/* include removed: duk_internal.h */
 
34169
 
 
34170
int duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
 
34171
        duk_uint32_t sanity;
 
34172
 
 
34173
        DUK_ASSERT(thr != NULL);
 
34174
        DUK_ASSERT(h != NULL);
 
34175
        /* allow 'p' to be NULL; then the result is always false */
 
34176
 
 
34177
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
34178
        do {
 
34179
                if (h == p) {
 
34180
                        return 1;
 
34181
                }
 
34182
 
 
34183
                if (sanity-- == 0) {
 
34184
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "prototype chain max depth reached (loop?)");
 
34185
                }
 
34186
                h = h->prototype;
 
34187
        } while (h);
 
34188
 
 
34189
        return 0;
 
34190
}
 
34191
 
 
34192
/* FIXME: needed? */
 
34193
void duk_hobject_set_prototype(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
 
34194
#ifdef DUK_USE_REFERENCE_COUNTING
 
34195
        duk_hobject *tmp;
 
34196
 
 
34197
        DUK_ASSERT(h);
 
34198
        tmp = h->prototype;
 
34199
        h->prototype = p;
 
34200
        DUK_HOBJECT_INCREF(thr, p);  /* avoid problems if p == h->prototype */
 
34201
        DUK_HOBJECT_DECREF(thr, tmp);
 
34202
#else
 
34203
        DUK_ASSERT(h);
 
34204
        h->prototype = p;
 
34205
#endif
 
34206
}
 
34207
 
 
34208
#line 1 "duk_hobject_pc2line.c"
 
34209
/*
 
34210
 *  Helpers for creating and querying pc2line debug data, which
 
34211
 *  converts a bytecode program counter to a source line number.
 
34212
 *
 
34213
 *  The run-time pc2line data is bit-packed, and documented in:
 
34214
 *
 
34215
 *    doc/function-objects.txt
 
34216
 */
 
34217
 
 
34218
/* include removed: duk_internal.h */
 
34219
 
 
34220
#if defined(DUK_USE_PC2LINE)
 
34221
 
 
34222
/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
 
34223
void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
 
34224
        duk_context *ctx = (duk_context *) thr;
 
34225
        duk_hbuffer_dynamic *h_buf;
 
34226
        duk_bitencoder_ctx be_ctx_alloc;
 
34227
        duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
 
34228
        duk_uint32_t *hdr;
 
34229
        duk_size_t new_size;
 
34230
        duk_uint_fast32_t num_header_entries;
 
34231
        duk_uint_fast32_t curr_offset;
 
34232
        duk_int_fast32_t curr_line, next_line, diff_line;
 
34233
        duk_uint_fast32_t curr_pc;
 
34234
        duk_uint_fast32_t hdr_index;
 
34235
 
 
34236
        DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
 
34237
 
 
34238
        /* FIXME: add proper spare handling to dynamic buffer, to minimize
 
34239
         * reallocs; currently there is no spare at all.
 
34240
         */
 
34241
 
 
34242
        num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
 
34243
        curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
 
34244
 
 
34245
        duk_push_dynamic_buffer(ctx, (size_t) curr_offset);
 
34246
        h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
34247
        DUK_ASSERT(h_buf != NULL);
 
34248
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf));
 
34249
 
 
34250
        hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h_buf);
 
34251
        DUK_ASSERT(hdr != NULL);
 
34252
        hdr[0] = (duk_uint32_t) length;  /* valid pc range is [0, length[ */
 
34253
 
 
34254
        curr_pc = 0U;
 
34255
        while (curr_pc < length) {
 
34256
                new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
 
34257
                duk_hbuffer_resize(thr, h_buf, new_size, new_size);
 
34258
 
 
34259
                hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h_buf);
 
34260
                DUK_ASSERT(hdr != NULL);
 
34261
                DUK_ASSERT(curr_pc < length);
 
34262
                hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
 
34263
                curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
 
34264
                hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
 
34265
                hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
 
34266
 
 
34267
#if 0
 
34268
                DUK_DDDPRINT("hdr[%d]: pc=%d line=%d offset=%d",
 
34269
                             (int) (curr_pc / DUK_PC2LINE_SKIP),
 
34270
                             (int) curr_pc,
 
34271
                             (int) hdr[hdr_index + 0],
 
34272
                             (int) hdr[hdr_index + 1]);
 
34273
#endif
 
34274
 
 
34275
                DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
 
34276
                be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
 
34277
                be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
 
34278
 
 
34279
                for (;;) {
 
34280
                        curr_pc++;
 
34281
                        if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) ||  /* end of diff run */
 
34282
                             (curr_pc >= length) ) {                 /* end of bytecode */
 
34283
                                break;
 
34284
                        }
 
34285
                        DUK_ASSERT(curr_pc < length);
 
34286
                        next_line = (duk_int32_t) instrs[curr_pc].line;
 
34287
                        diff_line = next_line - curr_line;
 
34288
 
 
34289
#if 0
 
34290
                        DUK_DDDPRINT("curr_line=%d, next_line=%d -> diff_line=%d",
 
34291
                                     (int) curr_line, (int) next_line, (int) diff_line);
 
34292
#endif
 
34293
 
 
34294
                        if (diff_line == 0) {
 
34295
                                /* 0 */
 
34296
                                duk_be_encode(be_ctx, 0, 1);
 
34297
                        } else if (diff_line >= 1 && diff_line <= 4) {
 
34298
                                /* 1 0 <2 bits> */
 
34299
                                duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
 
34300
                        } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
 
34301
                                /* 1 1 0 <8 bits> */
 
34302
                                DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
 
34303
                                duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
 
34304
                        } else {
 
34305
                                /* 1 1 1 <32 bits>
 
34306
                                 * Encode in two parts to avoid bitencode 24-bit limitation
 
34307
                                 */
 
34308
                                duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
 
34309
                                duk_be_encode(be_ctx, next_line & 0xffffU, 16);
 
34310
                        }
 
34311
 
 
34312
                        curr_line = next_line;
 
34313
                }
 
34314
 
 
34315
                duk_be_finish(be_ctx);
 
34316
                DUK_ASSERT(!be_ctx->truncated);
 
34317
 
 
34318
                /* be_ctx->offset == length of encoded bitstream */
 
34319
                curr_offset += (duk_uint_fast32_t) be_ctx->offset;
 
34320
        }
 
34321
 
 
34322
        /* compact */
 
34323
        new_size = (duk_size_t) curr_offset;
 
34324
        duk_hbuffer_resize(thr, h_buf, new_size, new_size);
 
34325
 
 
34326
        duk_to_fixed_buffer(ctx, -1);
 
34327
 
 
34328
        DUK_DDDPRINT("final pc2line data: pc_limit=%d, length=%d, %lf bits/opcode --> %!ixT",
 
34329
                     (int) length, (int) new_size, (double) new_size * 8.0 / (double) length,
 
34330
                     duk_get_tval(ctx, -1));
 
34331
}
 
34332
 
 
34333
/* PC is unsigned.  If caller does PC arithmetic and gets a negative result,
 
34334
 * it will map to a large PC which is out of bounds and causes a zero to be
 
34335
 * returned.
 
34336
 */
 
34337
duk_uint_fast32_t duk_hobject_pc2line_query(duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
 
34338
        duk_bitdecoder_ctx bd_ctx_alloc;
 
34339
        duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
 
34340
        duk_uint32_t *hdr;
 
34341
        duk_uint_fast32_t start_offset;
 
34342
        duk_uint_fast32_t pc_limit;
 
34343
        duk_uint_fast32_t hdr_index;
 
34344
        duk_uint_fast32_t pc_base;
 
34345
        duk_uint_fast32_t n;
 
34346
        duk_uint_fast32_t curr_line;
 
34347
 
 
34348
        DUK_ASSERT(buf != NULL);
 
34349
        DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf));
 
34350
 
 
34351
        hdr_index = pc / DUK_PC2LINE_SKIP;
 
34352
        pc_base = hdr_index * DUK_PC2LINE_SKIP;
 
34353
        n = pc - pc_base;
 
34354
 
 
34355
        if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
 
34356
                DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header");
 
34357
                goto error;
 
34358
        }
 
34359
 
 
34360
        hdr = (duk_uint32_t *) DUK_HBUFFER_FIXED_GET_DATA_PTR(buf);
 
34361
        pc_limit = hdr[0];
 
34362
        if (pc >= pc_limit) {
 
34363
                /* Note: pc is unsigned and cannot be negative */
 
34364
                DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%d, limit=%d)",
 
34365
                            (int) pc, (int) pc_limit);
 
34366
                goto error;
 
34367
        }
 
34368
 
 
34369
        curr_line = hdr[1 + hdr_index * 2];
 
34370
        start_offset = hdr[1 + hdr_index * 2 + 1];
 
34371
        if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
 
34372
                DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%d, buffer_size=%d)",
 
34373
                            (int) start_offset, (int) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf));
 
34374
                goto error;
 
34375
        }
 
34376
 
 
34377
        DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
 
34378
        bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
 
34379
        bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
 
34380
 
 
34381
#if 0
 
34382
        DUK_DDDPRINT("pc2line lookup: pc=%d -> hdr_index=%d, pc_base=%d, n=%d, start_offset=%d",
 
34383
                     (int) pc, (int) hdr_index, (int) pc_base, (int) n, (int) start_offset);
 
34384
#endif
 
34385
 
 
34386
        while (n > 0) {
 
34387
#if 0
 
34388
                DUK_DDDPRINT("lookup: n=%d, curr_line=%d", (int) n, (int) curr_line);
 
34389
#endif
 
34390
 
 
34391
                if (duk_bd_decode_flag(bd_ctx)) {
 
34392
                        if (duk_bd_decode_flag(bd_ctx)) {
 
34393
                                if (duk_bd_decode_flag(bd_ctx)) {
 
34394
                                        /* 1 1 1 <32 bits> */
 
34395
                                        duk_uint_fast32_t t;
 
34396
                                        t = duk_bd_decode(bd_ctx, 16);  /* workaround: max nbits = 24 now */
 
34397
                                        t = (t << 16) + duk_bd_decode(bd_ctx, 16);
 
34398
                                        curr_line = t;
 
34399
                                } else {
 
34400
                                        /* 1 1 0 <8 bits> */
 
34401
                                        duk_uint_fast32_t t;
 
34402
                                        t = duk_bd_decode(bd_ctx, 8);
 
34403
                                        curr_line = curr_line + t - 0x80;
 
34404
                                }
 
34405
                        } else {
 
34406
                                /* 1 0 <2 bits> */
 
34407
                                duk_uint_fast32_t t;
 
34408
                                t = duk_bd_decode(bd_ctx, 2);
 
34409
                                curr_line = curr_line + t + 1;
 
34410
                        }
 
34411
                } else {
 
34412
                        /* 0: no change */
 
34413
                }
 
34414
 
 
34415
                n--;
 
34416
        }
 
34417
 
 
34418
        DUK_DDDPRINT("pc2line lookup result: pc %d -> line %d", (int) pc, (int) curr_line);
 
34419
        return curr_line;
 
34420
 
 
34421
 error:
 
34422
        DUK_DPRINT("pc2line conversion failed for pc=%d", (int) pc);
 
34423
        return 0;
 
34424
}
 
34425
 
 
34426
#endif  /* DUK_USE_PC2LINE */
 
34427
#line 1 "duk_hobject_props.c"
 
34428
/*
 
34429
 *  Hobject property set/get functionality.
 
34430
 *
 
34431
 *  This is very central functionality for size, performance, and compliance.
 
34432
 *  It is also rather intricate; see hobject-algorithms.txt for discussion on
 
34433
 *  the algorithms and memory-management.txt for discussion on refcounts and
 
34434
 *  side effect issues.
 
34435
 *
 
34436
 *  Notes:
 
34437
 *
 
34438
 *    - It might be tempting to assert "refcount nonzero" for objects
 
34439
 *      being operated on, but that's not always correct: objects with
 
34440
 *      a zero refcount may be operated on by the refcount implementation
 
34441
 *      (finalization) for instance.  Hence, no refcount assertions are made.
 
34442
 *
 
34443
 *    - Many operations (memory allocation, identifier operations, etc)
 
34444
 *      may cause arbitrary side effects (e.g. through GC and finalization).
 
34445
 *      These side effects may invalidate duk_tval pointers which point to
 
34446
 *      areas subject to reallocation (like value stack).  Heap objects
 
34447
 *      themselves have stable pointers.  Holding heap object pointers or
 
34448
 *      duk_tval copies is not problematic with respect to side effects;
 
34449
 *      care must be taken when holding and using argument duk_tval pointers.
 
34450
 *
 
34451
 *    - If a finalizer is executed, it may operate on the the same object
 
34452
 *      we're currently dealing with.  For instance, the finalizer might
 
34453
 *      delete a certain property which has already been looked up and
 
34454
 *      confirmed to exist.  Ideally finalizers would be disabled if GC
 
34455
 *      happens during property access.  At the moment property table realloc
 
34456
 *      disables finalizers, and all DECREFs may cause arbitrary changes so
 
34457
 *      handle DECREF carefully.
 
34458
 *
 
34459
 *    - The order of operations for a DECREF matters.  When DECREF is executed,
 
34460
 *      the entire object graph must be consistent; note that a refzero may
 
34461
 *      lead to a mark-and-sweep through a refcount finalizer.
 
34462
 */
 
34463
 
 
34464
/* include removed: duk_internal.h */
 
34465
 
 
34466
/*
 
34467
 *  Local defines
 
34468
 */
 
34469
 
 
34470
#define DUK__NO_ARRAY_INDEX             DUK_HSTRING_NO_ARRAY_INDEX
 
34471
 
 
34472
/* hash probe sequence */
 
34473
#define DUK__HASH_INITIAL(hash,h_size)  DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
 
34474
#define DUK__HASH_PROBE_STEP(hash)      DUK_HOBJECT_HASH_PROBE_STEP((hash))
 
34475
 
 
34476
/* marker values for hash part */
 
34477
#define DUK__HASH_UNUSED                DUK_HOBJECT_HASHIDX_UNUSED
 
34478
#define DUK__HASH_DELETED               DUK_HOBJECT_HASHIDX_DELETED
 
34479
 
 
34480
/* assert value that suffices for all local calls, including recursion of
 
34481
 * other than Duktape calls (getters etc)
 
34482
 */
 
34483
#define DUK__VALSTACK_SPACE             10
 
34484
 
 
34485
/*
 
34486
 *  Local prototypes
 
34487
 */
 
34488
 
 
34489
static int duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
 
34490
static void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, int throw_flag);
 
34491
static void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
 
34492
 
 
34493
static int duk__handle_put_array_length_smaller(duk_hthread *thr, duk_hobject *obj, duk_uint32_t old_len, duk_uint32_t new_len, duk_uint32_t *out_result_len);
 
34494
static int duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
 
34495
 
 
34496
static int duk__get_property_desc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, int push_value);
 
34497
static int duk__get_own_property_desc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, int push_value);
 
34498
static int duk__get_own_property_desc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, int push_value);
 
34499
 
 
34500
/*
 
34501
 *  Misc helpers
 
34502
 */
 
34503
 
 
34504
/* Convert a duk_tval number (caller checks) to a 32-bit index.  Returns
 
34505
 * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
 
34506
 * index.
 
34507
 */
 
34508
static duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
 
34509
        duk_double_t dbl;
 
34510
        duk_uint32_t idx;
 
34511
 
 
34512
        DUK_ASSERT(tv != NULL);
 
34513
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
34514
 
 
34515
        dbl = DUK_TVAL_GET_NUMBER(tv);
 
34516
        idx = (duk_uint32_t) dbl;
 
34517
        if ((duk_double_t) idx == dbl) {
 
34518
                /* Is whole and within 32 bit range.  If the value happens to be 0xFFFFFFFF,
 
34519
                 * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
 
34520
                 */
 
34521
                return idx;
 
34522
        }
 
34523
        return DUK__NO_ARRAY_INDEX;
 
34524
}
 
34525
 
 
34526
/* Push an arbitrary duk_tval to the stack, coerce it to string, and return
 
34527
 * both a duk_hstring pointer and an array index (or DUK__NO_ARRAY_INDEX).
 
34528
 */
 
34529
static duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_tval *tv, duk_hstring **out_h) {
 
34530
        duk_uint32_t arr_idx;
 
34531
        duk_hstring *h;
 
34532
 
 
34533
        DUK_ASSERT(ctx != NULL);
 
34534
        DUK_ASSERT(tv != NULL);
 
34535
        DUK_ASSERT(out_h != NULL);
 
34536
 
 
34537
        duk_push_tval(ctx, tv);
 
34538
        duk_to_string(ctx, -1);
 
34539
        h = duk_get_hstring(ctx, -1);
 
34540
        DUK_ASSERT(h != NULL);
 
34541
        *out_h = h;
 
34542
 
 
34543
        arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
 
34544
        return arr_idx;
 
34545
}
 
34546
 
 
34547
/*
 
34548
 *  Helpers for managing property storage size
 
34549
 */
 
34550
 
 
34551
/* Get default hash part size for a certain entry part size. */
 
34552
static duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
 
34553
        DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
 
34554
 
 
34555
        if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
 
34556
                duk_uint32_t res;
 
34557
 
 
34558
                /* result: hash_prime(floor(1.2 * e_size)) */
 
34559
                res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
 
34560
 
 
34561
                /* if fails, e_size will be zero = not an issue, except performance-wise */
 
34562
                DUK_ASSERT(res == 0 || res > e_size);
 
34563
                return res;
 
34564
        } else {
 
34565
                return 0;
 
34566
        }
 
34567
}
 
34568
 
 
34569
/* Get minimum entry part growth for a certain size. */
 
34570
static duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
 
34571
        duk_uint32_t res;
 
34572
 
 
34573
        DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
 
34574
 
 
34575
        res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
 
34576
        DUK_ASSERT(res >= 1);  /* important for callers */
 
34577
        return res;
 
34578
}
 
34579
 
 
34580
/* Get minimum array part growth for a certain size. */
 
34581
static int duk__get_min_grow_a(int a_size) {
 
34582
        duk_uint32_t res;
 
34583
 
 
34584
        DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
 
34585
 
 
34586
        res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
 
34587
        DUK_ASSERT(res >= 1);  /* important for callers */
 
34588
        return res;
 
34589
}
 
34590
 
 
34591
/* Count actually used entry part entries (non-NULL keys). */
 
34592
static int duk__count_used_e_keys(duk_hobject *obj) {
 
34593
        duk_uint_fast32_t i;
 
34594
        int n = 0;
 
34595
        duk_hstring **e;
 
34596
 
 
34597
        DUK_ASSERT(obj != NULL);
 
34598
 
 
34599
        e = DUK_HOBJECT_E_GET_KEY_BASE(obj);
 
34600
        for (i = 0; i < obj->e_used; i++) {
 
34601
                if (*e++) {
 
34602
                        n++;
 
34603
                }
 
34604
        }
 
34605
        return n;
 
34606
}
 
34607
 
 
34608
/* Count actually used array part entries and array minimum size.
 
34609
 * NOTE: 'out_min_size' can be computed much faster by starting from the
 
34610
 * end and breaking out early when finding first used entry, but this is
 
34611
 * not needed now.
 
34612
 */
 
34613
static void duk__compute_a_stats(duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
 
34614
        unsigned int i;
 
34615
        duk_uint32_t used = 0;
 
34616
        duk_int32_t highest_idx = -1;
 
34617
        duk_tval *a;
 
34618
 
 
34619
        DUK_ASSERT(obj != NULL);
 
34620
        DUK_ASSERT(out_used != NULL);
 
34621
        DUK_ASSERT(out_min_size != NULL);
 
34622
 
 
34623
        a = DUK_HOBJECT_A_GET_BASE(obj);
 
34624
        for (i = 0; i < obj->a_size; i++) {
 
34625
                duk_tval *tv = a++;
 
34626
                if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
34627
                        used++;
 
34628
                        highest_idx = i;
 
34629
                }
 
34630
        }
 
34631
 
 
34632
        *out_used = used;
 
34633
        *out_min_size = highest_idx + 1;  /* 0 if no used entries */
 
34634
}
 
34635
 
 
34636
/* Check array density and indicate whether or not the array part should be abandoned. */
 
34637
static int duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
 
34638
        /*
 
34639
         *  Array abandon check; abandon if:
 
34640
         *
 
34641
         *    new_used / new_size < limit
 
34642
         *    new_used < limit * new_size        || limit is 3 bits fixed point
 
34643
         *    new_used < limit' / 8 * new_size   || *8
 
34644
         *    8*new_used < limit' * new_size     || :8
 
34645
         *    new_used < limit' * (new_size / 8)
 
34646
         *
 
34647
         *  Here, new_used = a_used, new_size = a_size.
 
34648
         *
 
34649
         *  Note: some callers use approximate values for a_used and/or a_size
 
34650
         *  (e.g. dropping a '+1' term).  This doesn't affect the usefulness
 
34651
         *  of the check, but may confuse debugging.
 
34652
         */
 
34653
 
 
34654
        return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
 
34655
}
 
34656
 
 
34657
/* Fast check for extending array: check whether or not a slow density check is required. */
 
34658
static int duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
 
34659
        /*
 
34660
         *  In a fast check we assume old_size equals old_used (i.e., existing
 
34661
         *  array is fully dense).
 
34662
         *
 
34663
         *  Slow check if:
 
34664
         *
 
34665
         *    (new_size - old_size) / old_size > limit
 
34666
         *    new_size - old_size > limit * old_size
 
34667
         *    new_size > (1 + limit) * old_size        || limit' is 3 bits fixed point
 
34668
         *    new_size > (1 + (limit' / 8)) * old_size || * 8
 
34669
         *    8 * new_size > (8 + limit') * old_size   || : 8
 
34670
         *    new_size > (8 + limit') * (old_size / 8)
 
34671
         *    new_size > limit'' * (old_size / 8)      || limit'' = 9 -> max 25% increase
 
34672
         *    arr_idx + 1 > limit'' * (old_size / 8)
 
34673
         *
 
34674
         *  This check doesn't work well for small values, so old_size is rounded
 
34675
         *  up for the check (and the '+ 1' of arr_idx can be ignored in practice):
 
34676
         *
 
34677
         *    arr_idx > limit'' * ((old_size + 7) / 8)
 
34678
         */
 
34679
 
 
34680
        return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
 
34681
}
 
34682
        
 
34683
/*
 
34684
 *  Reallocate property allocation, moving properties to the new allocation.
 
34685
 *
 
34686
 *  Includes key compaction, rehashing, and can also optionally abandoning
 
34687
 *  the array part, 'migrating' array entries into the beginning of the
 
34688
 *  new entry part.  Arguments are not validated here, so e.g. new_h_size
 
34689
 *  MUST be a valid prime.
 
34690
 *
 
34691
 *  There is no support for in-place reallocation or just compacting keys
 
34692
 *  without resizing the property allocation.  This is intentional to keep
 
34693
 *  code size minimal.
 
34694
 *
 
34695
 *  The implementation is relatively straightforward, except for the array
 
34696
 *  abandonment process.  Array abandonment requires that new string keys
 
34697
 *  are interned, which may trigger GC.  All keys interned so far must be
 
34698
 *  reachable for GC at all times; valstack is used for that now.
 
34699
 *
 
34700
 *  Also, a GC triggered during this reallocation process must not interfere
 
34701
 *  with the object being resized.  This is currently controlled by using
 
34702
 *  heap->mark_and_sweep_base_flags to indicate that no finalizers will be
 
34703
 *  executed (as they can affect ANY object) and no objects are compacted
 
34704
 *  (it would suffice to protect this particular object only, though).
 
34705
 *
 
34706
 *  Note: a non-checked variant would be nice but is a bit tricky to
 
34707
 *  implement for the array abandonment process.  It's easy for
 
34708
 *  everything else.
 
34709
 *
 
34710
 *  Note: because we need to potentially resize the valstack (as part
 
34711
 *  of abandoning the array part), any tval pointers to the valstack
 
34712
 *  will become invalid after this call.
 
34713
 */
 
34714
 
 
34715
static void duk__realloc_props(duk_hthread *thr,
 
34716
                               duk_hobject *obj,
 
34717
                               duk_uint32_t new_e_size,
 
34718
                               duk_uint32_t new_a_size,
 
34719
                               duk_uint32_t new_h_size,
 
34720
                               int abandon_array) {
 
34721
        duk_context *ctx = (duk_context *) thr;
 
34722
#ifdef DUK_USE_MARK_AND_SWEEP
 
34723
        int prev_mark_and_sweep_base_flags;
 
34724
#endif
 
34725
        duk_uint32_t new_alloc_size;
 
34726
        duk_uint32_t new_e_size_adjusted;
 
34727
        duk_uint8_t *new_p;
 
34728
        duk_hstring **new_e_k;
 
34729
        duk_propvalue *new_e_pv;
 
34730
        duk_uint8_t *new_e_f;
 
34731
        duk_tval *new_a;
 
34732
        duk_uint32_t *new_h;
 
34733
        duk_uint32_t new_e_used;
 
34734
        duk_uint_fast32_t i;
 
34735
 
 
34736
        DUK_ASSERT(thr != NULL);
 
34737
        DUK_ASSERT(ctx != NULL);
 
34738
        DUK_ASSERT(obj != NULL);
 
34739
        DUK_ASSERT(!abandon_array || new_a_size == 0);  /* if abandon_array, new_a_size must be 0 */
 
34740
        DUK_ASSERT(obj->p != NULL || (obj->e_size == 0 && obj->a_size == 0));
 
34741
        DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size);  /* required to guarantee success of rehashing,
 
34742
                                                                   * intentionally use unadjusted new_e_size
 
34743
                                                                   */   
 
34744
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
34745
 
 
34746
        /*
 
34747
         *  Pre resize assertions.
 
34748
         */
 
34749
 
 
34750
#ifdef DUK_USE_ASSERTIONS
 
34751
        /* XXX: pre checks (such as no duplicate keys) */
 
34752
#endif
 
34753
 
 
34754
        /*
 
34755
         *  For property layout 1, tweak e_size to ensure that the whole entry
 
34756
         *  part (key + val + flags) is a suitable multiple for alignment
 
34757
         *  (platform specific).
 
34758
         *
 
34759
         *  Property layout 2 does not require this tweaking and is preferred
 
34760
         *  on low RAM platforms requiring alignment.
 
34761
         */
 
34762
 
 
34763
#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
 
34764
        DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %d", (int) new_e_size);
 
34765
        new_e_size_adjusted = new_e_size;
 
34766
#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
 
34767
        DUK_DDDPRINT("using layout 1, but no need to pad e_size: %d", (int) new_e_size);
 
34768
        new_e_size_adjusted = new_e_size;
 
34769
#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
 
34770
        new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
 
34771
        DUK_DDDPRINT("using layout 1, and alignment target is %d, adjusted e_size: %d -> %d",
 
34772
                     (int) DUK_HOBJECT_ALIGN_TARGET, (int) new_e_size, (int) new_e_size_adjusted);
 
34773
        DUK_ASSERT(new_e_size_adjusted >= new_e_size);
 
34774
#else
 
34775
#error invalid hobject layout defines
 
34776
#endif
 
34777
 
 
34778
        /*
 
34779
         *  Debug logging after adjustment.
 
34780
         */
 
34781
 
 
34782
        DUK_DDDPRINT("attempt to resize hobject %p props (%d -> %d bytes), from {p=%p,e_size=%d,e_used=%d,a_size=%d,h_size=%d} to "
 
34783
                     "{e_size=%d,a_size=%d,h_size=%d}, abandon_array=%d, unadjusted new_e_size=%d",
 
34784
                     (void *) obj,
 
34785
                     DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size),
 
34786
                     DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
 
34787
                     (void *) obj->p,
 
34788
                     (int) obj->e_size,
 
34789
                     (int) obj->e_used,
 
34790
                     (int) obj->a_size,
 
34791
                     (int) obj->h_size,
 
34792
                     (int) new_e_size_adjusted,
 
34793
                     (int) new_a_size,
 
34794
                     (int) new_h_size,
 
34795
                     abandon_array,
 
34796
                     new_e_size);
 
34797
 
 
34798
        /*
 
34799
         *  Property count check.  This is the only point where we ensure that
 
34800
         *  we don't get more (allocated) property space that we can handle.
 
34801
         *  There aren't hard limits as such, but some algorithms fail (e.g.
 
34802
         *  finding next higher prime, selecting hash part size) if we get too
 
34803
         *  close to the 4G property limit.
 
34804
         *
 
34805
         *  Since this works based on allocation size (not actually used size),
 
34806
         *  the limit is a bit approximate but good enough in practice.
 
34807
         */
 
34808
 
 
34809
        if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
 
34810
                DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "object property limit reached");
 
34811
        }
 
34812
 
 
34813
        /*
 
34814
         *  Compute new alloc size and alloc new area.
 
34815
         *
 
34816
         *  The new area is allocated as a dynamic buffer and placed into the
 
34817
         *  valstack for reachability.  The actual buffer is then detached at
 
34818
         *  the end.
 
34819
         *
 
34820
         *  Note: heap_mark_and_sweep_base_flags are altered here to ensure
 
34821
         *  no-one touches this object while we're resizing and rehashing it.
 
34822
         *  The flags must be reset on every exit path after it.  Finalizers
 
34823
         *  and compaction is prevented currently for all objects while it
 
34824
         *  would be enough to restrict it only for the current object.
 
34825
         */
 
34826
 
 
34827
#ifdef DUK_USE_MARK_AND_SWEEP
 
34828
        prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
 
34829
        thr->heap->mark_and_sweep_base_flags |=
 
34830
                DUK_MS_FLAG_NO_FINALIZERS |         /* avoid attempts to add/remove object keys */
 
34831
                DUK_MS_FLAG_NO_OBJECT_COMPACTION;   /* avoid attempt to compact the current object */
 
34832
#endif
 
34833
 
 
34834
        new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
 
34835
        DUK_DDDPRINT("new hobject allocation size is %d", new_alloc_size);
 
34836
        if (new_alloc_size == 0) {
 
34837
                /* for zero size, don't push anything on valstack */
 
34838
                DUK_ASSERT(new_e_size_adjusted == 0);
 
34839
                DUK_ASSERT(new_a_size == 0);
 
34840
                DUK_ASSERT(new_h_size == 0);
 
34841
                new_p = NULL;
 
34842
        } else {
 
34843
                /* This may trigger mark-and-sweep with arbitrary side effects,
 
34844
                 * including an attempted resize of the object we're resizing,
 
34845
                 * executing a finalizer which may add or remove properties of
 
34846
                 * the object we're resizing etc.
 
34847
                 */
 
34848
 
 
34849
                /* Note: buffer is dynamic so that we can 'steal' the actual
 
34850
                 * allocation later.
 
34851
                 */
 
34852
 
 
34853
                new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size);  /* errors out if out of memory */
 
34854
                DUK_ASSERT(new_p != NULL);  /* since new_alloc_size > 0 */
 
34855
        }
 
34856
 
 
34857
        /* Set up pointers to the new property area: this is hidden behind a macro
 
34858
         * because it is memory layout specific.
 
34859
         */
 
34860
        DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
 
34861
                                       new_e_size_adjusted, new_a_size, new_h_size);
 
34862
        new_e_used = 0;
 
34863
 
 
34864
        /* if new_p == NULL, all of these pointers are NULL */
 
34865
        DUK_ASSERT((new_p != NULL) ||
 
34866
                   (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
 
34867
                    new_a == NULL && new_h == NULL));
 
34868
 
 
34869
        DUK_DDDPRINT("new alloc size %d, new_e_k=%p, new_e_pv=%p, new_e_f=%p, new_a=%p, new_h=%p",
 
34870
                     new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
 
34871
                     (void *) new_a, (void *) new_h);
 
34872
 
 
34873
        /*
 
34874
         *  Migrate array to start of entries if requested.
 
34875
         *
 
34876
         *  Note: from an enumeration perspective the order of entry keys matters.
 
34877
         *  Array keys should appear wherever they appeared before the array abandon
 
34878
         *  operation.
 
34879
         */
 
34880
 
 
34881
        if (abandon_array) {
 
34882
                /*
 
34883
                 *  Note: assuming new_a_size == 0, and that entry part contains
 
34884
                 *  no conflicting keys, refcounts do not need to be adjusted for
 
34885
                 *  the values, as they remain exactly the same.
 
34886
                 *
 
34887
                 *  The keys, however, need to be interned, incref'd, and be
 
34888
                 *  reachable for GC.  Any intern attempt may trigger a GC and
 
34889
                 *  claim any non-reachable strings, so every key must be reachable
 
34890
                 *  at all times.
 
34891
                 *
 
34892
                 *  A longjmp must not occur here, as the new_p allocation would
 
34893
                 *  be freed without these keys being decref'd, hence the messy
 
34894
                 *  decref handling if intern fails.
 
34895
                 */
 
34896
                DUK_ASSERT(new_a_size == 0);
 
34897
 
 
34898
                for (i = 0; i < obj->a_size; i++) {
 
34899
                        duk_tval *tv1;
 
34900
                        duk_tval *tv2;
 
34901
                        duk_hstring *key;
 
34902
 
 
34903
                        DUK_ASSERT(obj->p != NULL);
 
34904
 
 
34905
                        tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(obj, i);
 
34906
                        if (DUK_TVAL_IS_UNDEFINED_UNUSED(tv1)) {
 
34907
                                continue;
 
34908
                        }
 
34909
 
 
34910
                        DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
 
34911
                                   new_e_pv != NULL && new_e_f != NULL);
 
34912
 
 
34913
                        /*
 
34914
                         *  Intern key via the valstack to ensure reachability behaves
 
34915
                         *  properly.  We must avoid longjmp's here so use non-checked
 
34916
                         *  primitives.
 
34917
                         *
 
34918
                         *  Note: duk_check_stack() potentially reallocs the valstack,
 
34919
                         *  invalidating any duk_tval pointers to valstack.  Callers
 
34920
                         *  must be careful.
 
34921
                         */
 
34922
 
 
34923
                        /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
 
34924
                        if (!duk_check_stack(ctx, 1)) {
 
34925
                                goto abandon_error;
 
34926
                        }
 
34927
                        DUK_ASSERT_VALSTACK_SPACE(thr, 1);
 
34928
                        key = duk_heap_string_intern_u32(thr->heap, i);
 
34929
                        if (!key) {
 
34930
                                goto abandon_error;
 
34931
                        }
 
34932
                        duk_push_hstring(ctx, key);  /* keep key reachable for GC etc; guaranteed not to fail */
 
34933
 
 
34934
                        /* key is now reachable in the valstack */
 
34935
 
 
34936
                        DUK_HSTRING_INCREF(thr, key);   /* second incref for the entry reference */
 
34937
                        new_e_k[new_e_used] = key;
 
34938
                        tv2 = &new_e_pv[new_e_used].v;  /* array entries are all plain values */
 
34939
                        DUK_TVAL_SET_TVAL(tv2, tv1);
 
34940
                        new_e_f[new_e_used] = DUK_PROPDESC_FLAG_WRITABLE |
 
34941
                                              DUK_PROPDESC_FLAG_ENUMERABLE |
 
34942
                                              DUK_PROPDESC_FLAG_CONFIGURABLE;
 
34943
                        new_e_used++;
 
34944
 
 
34945
                        /* Note: new_e_used matches pushed temp key count, and nothing can
 
34946
                         * fail above between the push and this point.
 
34947
                         */
 
34948
                }
 
34949
 
 
34950
                DUK_DDDPRINT("abandon array: pop %d key temps from valstack", new_e_used);
 
34951
                duk_pop_n(ctx, new_e_used);
 
34952
        }
 
34953
 
 
34954
        /*
 
34955
         *  Copy keys and values in the entry part (compacting them at the same time).
 
34956
         */
 
34957
 
 
34958
        for (i = 0; i < obj->e_used; i++) {
 
34959
                duk_hstring *key;
 
34960
 
 
34961
                DUK_ASSERT(obj->p != NULL);
 
34962
 
 
34963
                key = DUK_HOBJECT_E_GET_KEY(obj, i);
 
34964
                if (!key) {
 
34965
                        continue;
 
34966
                }
 
34967
 
 
34968
                DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
 
34969
                           new_e_pv != NULL && new_e_f != NULL);
 
34970
 
 
34971
                new_e_k[new_e_used] = key;
 
34972
                new_e_pv[new_e_used] = DUK_HOBJECT_E_GET_VALUE(obj, i);
 
34973
                new_e_f[new_e_used] = DUK_HOBJECT_E_GET_FLAGS(obj, i);
 
34974
                new_e_used++;
 
34975
        }
 
34976
        /* the entries [new_e_used, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
 
34977
 
 
34978
        /*
 
34979
         *  Copy array elements to new array part.
 
34980
         */
 
34981
 
 
34982
        if (new_a_size > obj->a_size) {
 
34983
                /* copy existing entries as is */
 
34984
                DUK_ASSERT(new_p != NULL && new_a != NULL);
 
34985
                if (obj->a_size > 0) {
 
34986
                        /* avoid zero copy; if a_size == 0, obj->p might be NULL */
 
34987
                        DUK_ASSERT(obj->p != NULL);
 
34988
                        DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(obj), sizeof(duk_tval) * obj->a_size);
 
34989
                }
 
34990
 
 
34991
                /* fill new entries with -unused- (required, gc reachable) */
 
34992
                for (i = obj->a_size; i < new_a_size; i++) {
 
34993
                        duk_tval *tv = &new_a[i];
 
34994
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
34995
                }
 
34996
        } else {
 
34997
#ifdef DUK_USE_ASSERTIONS
 
34998
                /* caller must have decref'd values above new_a_size (if that is necessary) */
 
34999
                if (!abandon_array) {
 
35000
                        for (i = new_a_size; i < obj->a_size; i++) {
 
35001
                                duk_tval *tv;
 
35002
                                tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, i);
 
35003
 
 
35004
                                /* current assertion is quite strong: decref's and set to unused */
 
35005
                                DUK_ASSERT(DUK_TVAL_IS_UNDEFINED_UNUSED(tv));
 
35006
                        }
 
35007
                }
 
35008
#endif
 
35009
                if (new_a_size > 0) {
 
35010
                        /* avoid zero copy; if new_a_size == obj->a_size == 0, obj->p might be NULL */
 
35011
                        DUK_ASSERT(obj->a_size > 0);
 
35012
                        DUK_ASSERT(obj->p != NULL);
 
35013
                        DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(obj), sizeof(duk_tval) * new_a_size);
 
35014
                }
 
35015
        }
 
35016
 
 
35017
        /*
 
35018
         *  Rebuild the hash part always from scratch (guaranteed to finish).
 
35019
         *
 
35020
         *  Any resize of hash part requires rehashing.  In addition, by rehashing
 
35021
         *  get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
 
35022
         *  to ensuring the hash part never fills up.
 
35023
         */
 
35024
 
 
35025
        if (new_h_size > 0) {
 
35026
                DUK_ASSERT(new_h != NULL);
 
35027
 
 
35028
                /* fill new_h with u32 0xff = UNUSED */
 
35029
                DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
 
35030
 
 
35031
                DUK_ASSERT(new_e_used <= new_h_size);  /* equality not actually possible */
 
35032
                for (i = 0; i < new_e_used; i++) {
 
35033
                        duk_hstring *key = new_e_k[i];
 
35034
                        int j;  /* FIXME: typing */
 
35035
                        int step;
 
35036
 
 
35037
                        DUK_ASSERT(key != NULL);
 
35038
                        j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
 
35039
                        step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
 
35040
 
 
35041
                        for (;;) {
 
35042
                                DUK_ASSERT(new_h[j] != DUK__HASH_DELETED);  /* should never happen */
 
35043
                                if (new_h[j] == DUK__HASH_UNUSED) {
 
35044
                                        DUK_DDDPRINT("rebuild hit %d -> %d", j, i);
 
35045
                                        new_h[j] = i;
 
35046
                                        break;
 
35047
                                }
 
35048
                                DUK_DDDPRINT("rebuild miss %d, step %d", j, step);
 
35049
                                j = (j + step) % new_h_size;
 
35050
 
 
35051
                                /* guaranteed to finish */
 
35052
                                DUK_ASSERT(j != (int) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));  /* FIXME: typing */
 
35053
                        }
 
35054
                }
 
35055
        } else {
 
35056
                DUK_DDDPRINT("no hash part, no rehash");
 
35057
        }
 
35058
 
 
35059
        /*
 
35060
         *  Nice debug log.
 
35061
         */
 
35062
 
 
35063
        DUK_DDPRINT("resized hobject %p props (%d -> %d bytes), from {p=%p,e_size=%d,e_used=%d,a_size=%d,h_size=%d} to "
 
35064
                    "{p=%p,e_size=%d,e_used=%d,a_size=%d,h_size=%d}, abandon_array=%d, unadjusted new_e_size=%d",
 
35065
                    (void *) obj,
 
35066
                    DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size),
 
35067
                    (int) new_alloc_size,
 
35068
                    (void *) obj->p,
 
35069
                    (int) obj->e_size,
 
35070
                    (int) obj->e_used,
 
35071
                    (int) obj->a_size,
 
35072
                    (int) obj->h_size,
 
35073
                    (void *) new_p,
 
35074
                    (int) new_e_size_adjusted,
 
35075
                    (int) new_e_used,
 
35076
                    (int) new_a_size,
 
35077
                    (int) new_h_size,
 
35078
                    abandon_array,
 
35079
                    new_e_size);
 
35080
 
 
35081
        /*
 
35082
         *  All done, switch properties ('p') allocation to new one.
 
35083
         */
 
35084
 
 
35085
        DUK_FREE(thr->heap, obj->p);  /* NULL obj->p is OK */
 
35086
        obj->p = new_p;
 
35087
        obj->e_size = new_e_size_adjusted;
 
35088
        obj->e_used = new_e_used;
 
35089
        obj->a_size = new_a_size;
 
35090
        obj->h_size = new_h_size;
 
35091
 
 
35092
        if (new_p) {
 
35093
                /*
 
35094
                 *  Detach actual buffer from dynamic buffer in valstack, and
 
35095
                 *  pop it from the stack.
 
35096
                 *
 
35097
                 *  XXX: the buffer object is certainly not reachable at this point,
 
35098
                 *  so it would be nice to free it forcibly even with only
 
35099
                 *  mark-and-sweep enabled.  Not a big issue though.
 
35100
                 */
 
35101
                duk_hbuffer_dynamic *buf;
 
35102
                DUK_ASSERT(new_alloc_size > 0);
 
35103
                DUK_ASSERT(duk_is_buffer(ctx, -1));
 
35104
                buf = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, -1);
 
35105
                DUK_ASSERT(buf != NULL);
 
35106
                DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
 
35107
                buf->curr_alloc = NULL;
 
35108
                buf->size = 0;  /* these size resets are not strictly necessary, but nice for consistency */
 
35109
                buf->usable_size = 0;
 
35110
                duk_pop(ctx);
 
35111
        } else {
 
35112
                DUK_ASSERT(new_alloc_size == 0);
 
35113
                /* no need to pop, nothing was pushed */
 
35114
        }
 
35115
 
 
35116
        /* clear array part flag only after switching */
 
35117
        if (abandon_array) {
 
35118
                DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
 
35119
        }
 
35120
 
 
35121
        DUK_DDDPRINT("resize result: %!O", obj);
 
35122
 
 
35123
#ifdef DUK_USE_MARK_AND_SWEEP
 
35124
        thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
 
35125
#endif
 
35126
 
 
35127
        /*
 
35128
         *  Post resize assertions.
 
35129
         */
 
35130
 
 
35131
#ifdef DUK_USE_ASSERTIONS
 
35132
        /* XXX: post checks (such as no duplicate keys) */
 
35133
#endif
 
35134
        return;
 
35135
 
 
35136
        /*
 
35137
         *  Abandon array failed, need to decref keys already inserted
 
35138
         *  into the beginning of new_e_k before unwinding valstack.
 
35139
         */
 
35140
 
 
35141
 abandon_error:
 
35142
        DUK_DPRINT("hobject resize failed during abandon array, decref keys");
 
35143
        i = new_e_used;
 
35144
        while (i > 0) {
 
35145
                i--;
 
35146
                DUK_ASSERT(new_e_k != NULL);
 
35147
                DUK_ASSERT(new_e_k[i] != NULL);
 
35148
                DUK_HSTRING_DECREF(thr, new_e_k[i]);
 
35149
        }
 
35150
 
 
35151
#ifdef DUK_USE_MARK_AND_SWEEP
 
35152
        thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
 
35153
#endif
 
35154
 
 
35155
        DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "object resize failed (alloc/intern error)");
 
35156
}
 
35157
 
 
35158
/*
 
35159
 *  Helpers to resize properties allocation on specific needs.
 
35160
 */
 
35161
 
 
35162
/* Grow entry part allocation for one additional entry. */
 
35163
static void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
 
35164
        duk_uint32_t new_e_size;
 
35165
        duk_uint32_t new_a_size;
 
35166
        duk_uint32_t new_h_size;
 
35167
 
 
35168
        DUK_ASSERT(thr != NULL);
 
35169
        DUK_ASSERT(obj != NULL);
 
35170
 
 
35171
        new_e_size = obj->e_size + duk__get_min_grow_e(obj->e_size);
 
35172
        new_h_size = duk__get_default_h_size(new_e_size);
 
35173
        new_a_size = obj->a_size;
 
35174
        DUK_ASSERT(new_e_size >= obj->e_size + 1);  /* duk__get_min_grow_e() is always >= 1 */
 
35175
 
 
35176
        duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
 
35177
}
 
35178
 
 
35179
/* Grow array part for a new highest array index. */
 
35180
static void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
 
35181
        duk_uint32_t new_e_size;
 
35182
        duk_uint32_t new_a_size;
 
35183
        duk_uint32_t new_h_size;
 
35184
 
 
35185
        DUK_ASSERT(thr != NULL);
 
35186
        DUK_ASSERT(obj != NULL);
 
35187
        DUK_ASSERT(highest_arr_idx >= obj->a_size);
 
35188
 
 
35189
        /* minimum new length is highest_arr_idx + 1 */
 
35190
 
 
35191
        new_e_size = obj->e_size;
 
35192
        new_h_size = obj->h_size;
 
35193
        new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
 
35194
        DUK_ASSERT(new_a_size >= highest_arr_idx + 1);  /* duk__get_min_grow_a() is always >= 1 */
 
35195
 
 
35196
        duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
 
35197
}
 
35198
 
 
35199
/* Abandon array part, moving array entries into entries part.
 
35200
 * This requires a props resize, which is a heavy operation.
 
35201
 * We also compact the entries part while we're at it, although
 
35202
 * this is not strictly required.
 
35203
 */
 
35204
static void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
 
35205
        duk_uint32_t new_e_size;
 
35206
        duk_uint32_t new_a_size;
 
35207
        duk_uint32_t new_h_size;
 
35208
        duk_uint32_t e_used;
 
35209
        duk_uint32_t a_used;
 
35210
        duk_uint32_t a_size;
 
35211
 
 
35212
        DUK_ASSERT(thr != NULL);
 
35213
        DUK_ASSERT(obj != NULL);
 
35214
 
 
35215
        e_used = duk__count_used_e_keys(obj);
 
35216
        duk__compute_a_stats(obj, &a_used, &a_size);
 
35217
 
 
35218
        /*
 
35219
         *  Must guarantee all actually used array entries will fit into
 
35220
         *  new entry part.  Add one growth step to ensure we don't run out
 
35221
         *  of space right away.
 
35222
         */
 
35223
 
 
35224
        new_e_size = e_used + a_used;
 
35225
        new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
 
35226
        new_a_size = 0;
 
35227
        new_h_size = duk__get_default_h_size(new_e_size);
 
35228
 
 
35229
        DUK_DDPRINT("abandon array part for hobject %p, "
 
35230
                    "array stats before: e_used=%d, a_used=%d, a_size=%d; "
 
35231
                    "resize to e_size=%d, a_size=%d, h_size=%d",
 
35232
                    (void *) obj, e_used, a_used, a_size,
 
35233
                    new_e_size, new_a_size, new_h_size);
 
35234
 
 
35235
        duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
 
35236
}
 
35237
 
 
35238
/*
 
35239
 *  Compact an object.  Minimizes allocation size for objects which are
 
35240
 *  not likely to be extended.  This is useful for internal and non-
 
35241
 *  extensible objects, but can also be called for non-extensible objects.
 
35242
 *  May abandon the array part if it is computed to be too sparse.
 
35243
 *
 
35244
 *  This call is relatively expensive, as it needs to scan both the
 
35245
 *  entries and the array part.
 
35246
 *
 
35247
 *  The call may fail due to allocation error.
 
35248
 */
 
35249
 
 
35250
void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
 
35251
        duk_uint32_t e_size;       /* currently used -> new size */
 
35252
        duk_uint32_t a_size;       /* currently required */
 
35253
        duk_uint32_t a_used;       /* actually used */
 
35254
        duk_uint32_t h_size;
 
35255
        int abandon_array;
 
35256
 
 
35257
        DUK_ASSERT(thr != NULL);
 
35258
        DUK_ASSERT(obj != NULL);
 
35259
 
 
35260
        e_size = duk__count_used_e_keys(obj);
 
35261
        duk__compute_a_stats(obj, &a_used, &a_size);
 
35262
 
 
35263
        DUK_DDPRINT("compacting hobject, used e keys %d, used a keys %d, min a size %d, "
 
35264
                    "resized array density would be: %d/%d = %d",
 
35265
                    e_size, a_used, a_size,
 
35266
                    a_used, a_size,
 
35267
                    (double) a_used / (double) a_size);
 
35268
 
 
35269
        if (duk__abandon_array_density_check(a_used, a_size)) {
 
35270
                DUK_DDPRINT("decided to abandon array during compaction, a_used=%d, a_size=%d",
 
35271
                            a_used, a_size);
 
35272
                abandon_array = 1;
 
35273
                e_size += a_used;
 
35274
                a_size = 0;
 
35275
        } else {
 
35276
                DUK_DDPRINT("decided to keep array during compaction");
 
35277
                abandon_array = 0;
 
35278
        }
 
35279
 
 
35280
        if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
 
35281
                h_size = duk__get_default_h_size(e_size);
 
35282
        } else {
 
35283
                h_size = 0;
 
35284
        }
 
35285
 
 
35286
        DUK_DDPRINT("compacting hobject -> new e_size %d, new a_size=%d, new h_size=%d, abandon_array=%d",
 
35287
                    e_size, a_size, h_size, abandon_array);
 
35288
 
 
35289
        duk__realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
 
35290
}
 
35291
 
 
35292
/*
 
35293
 *  Find an existing key from entry part either by linear scan or by
 
35294
 *  using the hash index (if it exists).
 
35295
 *
 
35296
 *  Sets entry index (and possibly the hash index) to output variables,
 
35297
 *  which allows the caller to update the entry and hash entries in-place.
 
35298
 *  If entry is not found, both values are set to -1.  If entry is found
 
35299
 *  but there is no hash part, h_idx is set to -1.
 
35300
 */
 
35301
 
 
35302
void duk_hobject_find_existing_entry(duk_hobject *obj, duk_hstring *key, int *e_idx, int *h_idx) {
 
35303
        DUK_ASSERT(obj != NULL);
 
35304
        DUK_ASSERT(key != NULL);
 
35305
        DUK_ASSERT(e_idx != NULL);
 
35306
        DUK_ASSERT(h_idx != NULL);
 
35307
 
 
35308
        if (DUK_LIKELY(obj->h_size == 0)) {
 
35309
                /* linear scan: more likely because most objects are small */
 
35310
                duk_uint_fast32_t i;
 
35311
                duk_uint_fast32_t n;
 
35312
                duk_hstring **h_keys_base;
 
35313
                DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup");
 
35314
 
 
35315
                h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(obj);
 
35316
                n = obj->e_used;
 
35317
                for (i = 0; i < n; i++) {
 
35318
                        if (h_keys_base[i] == key) {
 
35319
                                *e_idx = i;
 
35320
                                *h_idx = -1;
 
35321
                                return;
 
35322
                        }
 
35323
                }
 
35324
        } else {
 
35325
                /* hash lookup */
 
35326
                int i;
 
35327
                int n;
 
35328
                int step;
 
35329
                duk_uint32_t *h_base;
 
35330
 
 
35331
                DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup");
 
35332
 
 
35333
                h_base = DUK_HOBJECT_H_GET_BASE(obj);
 
35334
                n = obj->h_size;
 
35335
                i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
 
35336
                step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
 
35337
 
 
35338
                for (;;) {
 
35339
                        duk_uint32_t t;
 
35340
 
 
35341
                        DUK_ASSERT(i >= 0);
 
35342
                        DUK_ASSERT((duk_size_t) i < obj->h_size);  /* FIXME: typing */
 
35343
                        t = h_base[i];
 
35344
                        DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
 
35345
                                   (t < obj->e_size));  /* t >= 0 always true, unsigned */
 
35346
 
 
35347
                        if (t == DUK__HASH_UNUSED) {
 
35348
                                break;
 
35349
                        } else if (t == DUK__HASH_DELETED) {
 
35350
                                DUK_DDDPRINT("lookup miss (deleted) i=%d, t=%d", i, t);
 
35351
                        } else {
 
35352
                                DUK_ASSERT(t < obj->e_size);
 
35353
                                if (DUK_HOBJECT_E_GET_KEY(obj, t) == key) {
 
35354
                                        DUK_DDDPRINT("lookup hit i=%d, t=%d -> key %p", i, t, (void *) key);
 
35355
                                        *e_idx = t;
 
35356
                                        *h_idx = i;
 
35357
                                        return;
 
35358
                                }
 
35359
                                DUK_DDDPRINT("lookup miss i=%d, t=%d", i, t);
 
35360
                        }
 
35361
                        i = (i + step) % n;
 
35362
 
 
35363
                        /* guaranteed to finish, as hash is never full */
 
35364
                        DUK_ASSERT(i != (int) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));  /* FIXME: typing */
 
35365
                }
 
35366
        }
 
35367
 
 
35368
        /* not found */
 
35369
        *e_idx = -1;
 
35370
        *h_idx = -1;
 
35371
}
 
35372
 
 
35373
/* For internal use: get non-accessor entry value */
 
35374
duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_hobject *obj, duk_hstring *key) {
 
35375
        int e_idx;
 
35376
        int h_idx;
 
35377
 
 
35378
        DUK_ASSERT(obj != NULL);
 
35379
        DUK_ASSERT(key != NULL);
 
35380
 
 
35381
        duk_hobject_find_existing_entry(obj, key, &e_idx, &h_idx);
 
35382
        if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, e_idx)) {
 
35383
                return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx);
 
35384
        } else {
 
35385
                return NULL;
 
35386
        }
 
35387
}
 
35388
 
 
35389
/* For internal use: get non-accessor entry value and attributes */
 
35390
duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs) {
 
35391
        int e_idx;
 
35392
        int h_idx;
 
35393
 
 
35394
        DUK_ASSERT(obj != NULL);
 
35395
        DUK_ASSERT(key != NULL);
 
35396
        DUK_ASSERT(out_attrs != NULL);
 
35397
 
 
35398
        duk_hobject_find_existing_entry(obj, key, &e_idx, &h_idx);
 
35399
        if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, e_idx)) {
 
35400
                *out_attrs = DUK_HOBJECT_E_GET_FLAGS(obj, e_idx);
 
35401
                return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx);
 
35402
        } else {
 
35403
                *out_attrs = 0;
 
35404
                return NULL;
 
35405
        }
 
35406
}
 
35407
 
 
35408
/* For internal use: get array part value */
 
35409
duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_hobject *obj, duk_uint32_t i) {
 
35410
        duk_tval *tv;
 
35411
 
 
35412
        DUK_ASSERT(obj != NULL);
 
35413
 
 
35414
        if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
 
35415
                return NULL;
 
35416
        }
 
35417
        if (i >= obj->a_size) {
 
35418
                return NULL;
 
35419
        }
 
35420
        tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, i);
 
35421
        return tv;
 
35422
}
 
35423
 
 
35424
/*
 
35425
 *  Allocate and initialize a new entry, resizing the properties allocation
 
35426
 *  if necessary.  Returns entry index (e_idx) or throws an error if alloc fails.
 
35427
 *
 
35428
 *  Sets the key of the entry (increasing the key's refcount), and updates
 
35429
 *  the hash part if it exists.  Caller must set value and flags, and update
 
35430
 *  the entry value refcount.  A decref for the previous value is not necessary.
 
35431
 */
 
35432
 
 
35433
static int duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
 
35434
        duk_uint32_t idx;
 
35435
 
 
35436
        DUK_ASSERT(thr != NULL);
 
35437
        DUK_ASSERT(obj != NULL);
 
35438
        DUK_ASSERT(key != NULL);
 
35439
        DUK_ASSERT(obj->e_used <= obj->e_size);
 
35440
 
 
35441
#ifdef DUK_USE_ASSERTIONS
 
35442
        /* key must not already exist in entry part */
 
35443
        {
 
35444
                duk_uint_fast32_t i;
 
35445
                for (i = 0; i < obj->e_used; i++) {
 
35446
                        DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(obj, i) != key);
 
35447
                }
 
35448
        }
 
35449
#endif
 
35450
 
 
35451
        if (obj->e_used >= obj->e_size) {
 
35452
                /* only need to guarantee 1 more slot, but allocation growth is in chunks */
 
35453
                DUK_DDDPRINT("entry part full, allocate space for one more entry");
 
35454
                duk__grow_props_for_new_entry_item(thr, obj);
 
35455
        }
 
35456
        DUK_ASSERT(obj->e_used < obj->e_size);
 
35457
        idx = obj->e_used++;
 
35458
 
 
35459
        /* previous value is assumed to be garbage, so don't touch it */
 
35460
        DUK_HOBJECT_E_SET_KEY(obj, idx, key);
 
35461
        DUK_HSTRING_INCREF(thr, key);
 
35462
 
 
35463
        if (obj->h_size > 0) {
 
35464
                int i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), obj->h_size);
 
35465
                int step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
 
35466
                duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(obj);
 
35467
 
 
35468
                for (;;) {
 
35469
                        duk_uint32_t t = h_base[i];
 
35470
                        if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
 
35471
                                DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %d -> %d", i, idx);
 
35472
                                DUK_ASSERT(i >= 0);
 
35473
                                DUK_ASSERT((duk_size_t) i < obj->h_size);  /* FIXME: typing */
 
35474
                                DUK_ASSERT_DISABLE(idx >= 0);
 
35475
                                DUK_ASSERT(idx < obj->e_size);
 
35476
                                h_base[i] = idx;
 
35477
                                break;
 
35478
                        }
 
35479
                        DUK_DDDPRINT("duk__alloc_entry_checked() miss %d", i);
 
35480
                        i = (i + step) % obj->h_size;
 
35481
 
 
35482
                        /* guaranteed to find an empty slot */
 
35483
                        DUK_ASSERT(i != (int) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), obj->h_size));  /* FIXME: typing */
 
35484
                }
 
35485
        }
 
35486
 
 
35487
        /* Note: we could return the hash index here too, but it's not
 
35488
         * needed right now.
 
35489
         */
 
35490
 
 
35491
        DUK_ASSERT_DISABLE(idx >= 0);
 
35492
        DUK_ASSERT(idx < obj->e_size);
 
35493
        DUK_ASSERT(idx < obj->e_used);
 
35494
        return idx;
 
35495
}
 
35496
 
 
35497
/*
 
35498
 *  Object internal value
 
35499
 *
 
35500
 *  Returned value is guaranteed to be reachable / incref'd, caller does not need 
 
35501
 *  to incref OR decref.
 
35502
 */
 
35503
 
 
35504
/* FIXME: is this wrapper useful?  just a 'get_own_prop' call and normal stack ops? */
 
35505
 
 
35506
int duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
 
35507
        int e_idx;
 
35508
        int h_idx;
 
35509
 
 
35510
        DUK_ASSERT(heap != NULL);
 
35511
        DUK_ASSERT(obj != NULL);
 
35512
        DUK_ASSERT(tv_out != NULL);
 
35513
 
 
35514
        DUK_TVAL_SET_UNDEFINED_UNUSED(tv_out);
 
35515
 
 
35516
        /* always in entry part, no need to look up parents etc */
 
35517
        duk_hobject_find_existing_entry(obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
 
35518
        if (e_idx >= 0) {
 
35519
                DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, e_idx));
 
35520
                DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx));
 
35521
                return 1;
 
35522
        }
 
35523
        return 0;
 
35524
}
 
35525
 
 
35526
duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
 
35527
        duk_tval tv;
 
35528
 
 
35529
        DUK_ASSERT(heap != NULL);
 
35530
        DUK_ASSERT(obj != NULL);
 
35531
 
 
35532
        if (duk_hobject_get_internal_value(heap, obj, &tv)) {
 
35533
                duk_hstring *h;
 
35534
                DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
 
35535
                h = DUK_TVAL_GET_STRING(&tv);
 
35536
                return h;
 
35537
        }
 
35538
 
 
35539
        return NULL;
 
35540
}
 
35541
 
 
35542
duk_hbuffer *duk_hobject_get_internal_value_buffer(duk_heap *heap, duk_hobject *obj) {
 
35543
        duk_tval tv;
 
35544
 
 
35545
        DUK_ASSERT(heap != NULL);
 
35546
        DUK_ASSERT(obj != NULL);
 
35547
 
 
35548
        if (duk_hobject_get_internal_value(heap, obj, &tv)) {
 
35549
                duk_hbuffer *h;
 
35550
                DUK_ASSERT(DUK_TVAL_IS_BUFFER(&tv));
 
35551
                h = DUK_TVAL_GET_BUFFER(&tv);
 
35552
                return h;
 
35553
        }
 
35554
 
 
35555
        return NULL;
 
35556
}
 
35557
 
 
35558
/*
 
35559
 *  Arguments handling helpers (argument map mainly).
 
35560
 *
 
35561
 *  An arguments object has special behavior for some numeric indices.
 
35562
 *  Accesses may translate to identifier operations which may have
 
35563
 *  arbitrary side effects (potentially invalidating any duk_tval
 
35564
 *  pointers).
 
35565
 */
 
35566
 
 
35567
/* Lookup 'key' from arguments internal 'map', perform a variable lookup
 
35568
 * if mapped, and leave the result on top of stack (and return non-zero).
 
35569
 * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
 
35570
 */
 
35571
static int duk__lookup_arguments_map(duk_hthread *thr,
 
35572
                                     duk_hobject *obj,
 
35573
                                     duk_hstring *key,
 
35574
                                     duk_propdesc *temp_desc,
 
35575
                                     duk_hobject **out_map,
 
35576
                                     duk_hobject **out_varenv) {
 
35577
        duk_context *ctx = (duk_context *) thr;
 
35578
        duk_hobject *map;
 
35579
        duk_hobject *varenv;
 
35580
        int rc;
 
35581
 
 
35582
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
35583
 
 
35584
        DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
 
35585
                     "(obj -> %!O, key -> %!O)",
 
35586
                     (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
 
35587
                     obj, key);
 
35588
 
 
35589
        if (!duk__get_own_property_desc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, 1)) {  /* push_value = 1 */
 
35590
                DUK_DDDPRINT("-> no 'map'");
 
35591
                return 0;
 
35592
        }
 
35593
 
 
35594
        map = duk_require_hobject(ctx, -1);
 
35595
        DUK_ASSERT(map != NULL);
 
35596
        duk_pop(ctx);  /* map is reachable through obj */
 
35597
        
 
35598
        if (!duk__get_own_property_desc(thr, map, key, temp_desc, 1)) {  /* push_value = 1 */
 
35599
                DUK_DDDPRINT("-> 'map' exists, but key not in map");
 
35600
                return 0;
 
35601
        }
 
35602
 
 
35603
        /* [... varname] */
 
35604
        DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
 
35605
                     duk_get_tval(ctx, -1));
 
35606
        DUK_ASSERT(duk_is_string(ctx, -1));  /* guaranteed when building arguments */
 
35607
 
 
35608
        /* get varenv for varname (callee's declarative lexical environment) */
 
35609
        rc = duk__get_own_property_desc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, 1);  /* push_value = 1 */
 
35610
        DUK_UNREF(rc);
 
35611
        DUK_ASSERT(rc != 0);  /* arguments MUST have an initialized lexical environment reference */
 
35612
        varenv = duk_require_hobject(ctx, -1);
 
35613
        DUK_ASSERT(varenv != NULL);
 
35614
        duk_pop(ctx);  /* varenv remains reachable through 'obj' */
 
35615
 
 
35616
        DUK_DDDPRINT("arguments varenv is: %!dO", varenv);
 
35617
 
 
35618
        /* success: leave varname in stack */
 
35619
        *out_map = map;
 
35620
        *out_varenv = varenv;
 
35621
        return 1;  /* [... varname] */
 
35622
}
 
35623
 
 
35624
/* Lookup 'key' from arguments internal 'map', and leave replacement value
 
35625
 * on stack top if mapped (and return non-zero).
 
35626
 * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
 
35627
 */
 
35628
static int duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
 
35629
        duk_context *ctx = (duk_context *) thr;
 
35630
        duk_hobject *map;
 
35631
        duk_hobject *varenv;
 
35632
        duk_hstring *varname;
 
35633
 
 
35634
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
35635
 
 
35636
        if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
 
35637
                DUK_DDDPRINT("arguments: key not mapped, no special get behavior");
 
35638
                return 0;
 
35639
        }
 
35640
 
 
35641
        /* [... varname] */
 
35642
 
 
35643
        varname = duk_require_hstring(ctx, -1);
 
35644
        DUK_ASSERT(varname != NULL);
 
35645
        duk_pop(ctx);  /* varname is still reachable */
 
35646
 
 
35647
        DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
 
35648
                     "key=%!O, varname=%!O",
 
35649
                     (duk_heaphdr *) key,
 
35650
                     (duk_heaphdr *) varname);
 
35651
 
 
35652
        (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
 
35653
 
 
35654
        /* [... value this_binding] */
 
35655
 
 
35656
        duk_pop(ctx);
 
35657
 
 
35658
        /* leave result on stack top */
 
35659
        return 1;
 
35660
}
 
35661
 
 
35662
/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
 
35663
 * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
 
35664
 * Assumes stack top contains 'put' value (which is NOT popped).
 
35665
 */
 
35666
static void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, int throw_flag) {
 
35667
        duk_context *ctx = (duk_context *) thr;
 
35668
        duk_hobject *map;
 
35669
        duk_hobject *varenv;
 
35670
        duk_hstring *varname;
 
35671
 
 
35672
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
35673
 
 
35674
        if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
 
35675
                DUK_DDDPRINT("arguments: key not mapped, no special put behavior");
 
35676
                return;
 
35677
        }
 
35678
 
 
35679
        /* [... put_value varname] */
 
35680
 
 
35681
        varname = duk_require_hstring(ctx, -1);
 
35682
        DUK_ASSERT(varname != NULL);
 
35683
        duk_pop(ctx);  /* varname is still reachable */
 
35684
 
 
35685
        DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
 
35686
                     "key=%!O, varname=%!O, value=%!T",
 
35687
                     (duk_heaphdr *) key,
 
35688
                     (duk_heaphdr *) varname,
 
35689
                     duk_require_tval(ctx, -1));
 
35690
 
 
35691
        /* [... put_value] */
 
35692
 
 
35693
        /*
 
35694
         *  Note: although arguments object variable mappings are only established
 
35695
         *  for non-strict functions (and a call to a non-strict function created
 
35696
         *  the arguments object in question), an inner strict function may be doing
 
35697
         *  the actual property write.  Hence the throw_flag applied here comes from
 
35698
         *  the property write call.
 
35699
         */
 
35700
 
 
35701
        duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
 
35702
 
 
35703
        /* [... put_value] */
 
35704
}
 
35705
 
 
35706
/* Lookup 'key' from arguments internal 'map', delete mapping if found.
 
35707
 * Used in E5 Section 10.6 algorithm for [[Delete]].  Note that the
 
35708
 * variable/argument itself (where the map points) is not deleted.
 
35709
 */
 
35710
static void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
 
35711
        duk_context *ctx = (duk_context *) thr;
 
35712
        duk_hobject *map;
 
35713
 
 
35714
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
35715
 
 
35716
        if (!duk__get_own_property_desc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, 1)) {  /* push_value = 1 */
 
35717
                DUK_DDDPRINT("arguments: key not mapped, no special delete behavior");
 
35718
                return;
 
35719
        }
 
35720
 
 
35721
        map = duk_require_hobject(ctx, -1);
 
35722
        DUK_ASSERT(map != NULL);
 
35723
        duk_pop(ctx);  /* map is reachable through obj */
 
35724
        
 
35725
        DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists); ignore result", key);
 
35726
 
 
35727
        /* Note: no recursion issue, we can trust 'map' to behave */
 
35728
        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_BEHAVIOR(map));
 
35729
        DUK_DDDPRINT("map before deletion: %!O", map);
 
35730
        (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
 
35731
        DUK_DDDPRINT("map after deletion: %!O", map);
 
35732
}
 
35733
 
 
35734
/*
 
35735
 *  Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
 
35736
 *
 
35737
 *  If property is found:
 
35738
 *    - Fills descriptor fields to 'out_desc'
 
35739
 *    - If 'push_value' is non-zero, pushes a value related to the
 
35740
 *      property onto the stack ('undefined' for accessor properties).
 
35741
 *    - Returns non-zero
 
35742
 *
 
35743
 *  If property is not found:
 
35744
 *    - 'out_desc' is left in untouched state (possibly garbage)
 
35745
 *    - Nothing is pushed onto the stack (not even with push_value set)
 
35746
 *    - Returns zero
 
35747
 *
 
35748
 *  Notes:
 
35749
 *
 
35750
 *    - Getting a property descriptor may cause an allocation (and hence
 
35751
 *      GC) to take place, hence reachability and refcount of all related
 
35752
 *      values matter.  Reallocation of value stack, properties, etc may
 
35753
 *      invalidate many duk_tval pointers (concretely, those which reside
 
35754
 *      in memory areas subject to reallocation).  However, heap object
 
35755
 *      pointers are never affected (heap objects have stable pointers).
 
35756
 *
 
35757
 *    - The value of a plain property is always reachable and has a non-zero
 
35758
 *      reference count.
 
35759
 *
 
35760
 *    - The value of a virtual property is not necessarily reachable from
 
35761
 *      elsewhere and may have a refcount of zero.  Hence we push it onto
 
35762
 *      the valstack for the caller, which ensures it remains reachable
 
35763
 *      while it is needed.
 
35764
 *
 
35765
 *    - There are no virtual accessor properties.  Hence, all getters and
 
35766
 *      setters are always related to concretely stored properties, which
 
35767
 *      ensures that the get/set functions in the resulting descriptor are
 
35768
 *      reachable and have non-zero refcounts.  Should there be virtual
 
35769
 *      accessor properties later, this would need to change.
 
35770
 */
 
35771
 
 
35772
static int duk__get_own_property_desc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, int push_value) {
 
35773
        duk_context *ctx = (duk_context *) thr;
 
35774
        duk_tval *tv;
 
35775
 
 
35776
        DUK_DDDPRINT("duk__get_own_property_desc: thr=%p, obj=%p, key=%p, out_desc=%p, push_value=%d, arr_idx=%d (obj -> %!O, key -> %!O)",
 
35777
                     (void *) thr, (void *) obj, (void *) key, (void *) out_desc, push_value, arr_idx,
 
35778
                     (duk_heaphdr *) obj, (duk_heaphdr *) key);
 
35779
 
 
35780
        DUK_ASSERT(ctx != NULL);
 
35781
        DUK_ASSERT(thr != NULL);
 
35782
        DUK_ASSERT(thr->heap != NULL);
 
35783
        DUK_ASSERT(obj != NULL);
 
35784
        DUK_ASSERT(key != NULL);
 
35785
        DUK_ASSERT(out_desc != NULL);
 
35786
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
35787
 
 
35788
        /* FIXME: optimize this filling behavior later */
 
35789
        out_desc->flags = 0;
 
35790
        out_desc->get = NULL;
 
35791
        out_desc->set = NULL;
 
35792
        out_desc->e_idx = -1;
 
35793
        out_desc->h_idx = -1;
 
35794
        out_desc->a_idx = -1;
 
35795
 
 
35796
        /*
 
35797
         *  Array part
 
35798
         */
 
35799
 
 
35800
        if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
 
35801
                if (arr_idx < obj->a_size) {
 
35802
                        tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, arr_idx);
 
35803
                        if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
35804
                                DUK_DDDPRINT("-> found in array part");
 
35805
                                if (push_value) {
 
35806
                                        duk_push_tval(ctx, tv);
 
35807
                                }
 
35808
                                /* implicit attributes */
 
35809
                                out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
 
35810
                                                  DUK_PROPDESC_FLAG_CONFIGURABLE |
 
35811
                                                  DUK_PROPDESC_FLAG_ENUMERABLE;
 
35812
                                out_desc->a_idx = arr_idx;
 
35813
                                goto prop_found;
 
35814
                        }
 
35815
                }
 
35816
                /* assume array part is comprehensive (contains all array indexed elements
 
35817
                 * or none of them); hence no need to check the entries part here.
 
35818
                 */
 
35819
                DUK_DDDPRINT("-> not found as a concrete property (has array part, "
 
35820
                             "should be there if present)");
 
35821
                goto prop_not_found_concrete;
 
35822
        }
 
35823
 
 
35824
        /*
 
35825
         *  Entries part
 
35826
         */
 
35827
 
 
35828
        duk_hobject_find_existing_entry(obj, key, &out_desc->e_idx, &out_desc->h_idx);
 
35829
        if (out_desc->e_idx >= 0) {
 
35830
                int e_idx = out_desc->e_idx;
 
35831
                out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(obj, e_idx);
 
35832
                if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
35833
                        DUK_DDDPRINT("-> found accessor property in entry part");
 
35834
                        out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(obj, e_idx);
 
35835
                        out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(obj, e_idx);
 
35836
                        if (push_value) {
 
35837
                                /* a dummy undefined value is pushed to make valstack
 
35838
                                 * behavior uniform for caller
 
35839
                                 */
 
35840
                                duk_push_undefined(ctx);
 
35841
                        }
 
35842
                } else {
 
35843
                        DUK_DDDPRINT("-> found plain property in entry part");
 
35844
                        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx);
 
35845
                        if (push_value) {
 
35846
                                duk_push_tval(ctx, tv);
 
35847
                        }
 
35848
                }
 
35849
                goto prop_found;
 
35850
        }
 
35851
 
 
35852
        /*
 
35853
         *  Not found as a concrete property, check whether a String object
 
35854
         *  virtual property matches.
 
35855
         */
 
35856
 
 
35857
 prop_not_found_concrete:
 
35858
 
 
35859
        if (DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj)) {
 
35860
                DUK_DDDPRINT("string object special property get for key: %!O, arr_idx: %d", key, arr_idx);
 
35861
 
 
35862
                if (arr_idx != DUK__NO_ARRAY_INDEX) {
 
35863
                        duk_hstring *h_val;
 
35864
 
 
35865
                        DUK_DDDPRINT("array index exists");
 
35866
 
 
35867
                        h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
 
35868
                        DUK_ASSERT(h_val);
 
35869
                        if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
 
35870
                                DUK_DDDPRINT("-> found, array index inside string");
 
35871
                                if (push_value) {
 
35872
                                        duk_push_hstring(ctx, h_val);
 
35873
                                        duk_substring(ctx, -1, arr_idx, arr_idx + 1);  /* [str] -> [substr] */
 
35874
                                }
 
35875
                                out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE |  /* E5 Section 15.5.5.2 */
 
35876
                                                  DUK_PROPDESC_FLAG_VIRTUAL;
 
35877
 
 
35878
                                DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
 
35879
                                return 1;  /* cannot be e.g. arguments special, since special 'traits' are mutually exclusive */
 
35880
                        } else {
 
35881
                                /* index is above internal string length -> property is fully normal */
 
35882
                                DUK_DDDPRINT("array index outside string -> normal property");
 
35883
                        }
 
35884
                } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
35885
                        duk_hstring *h_val;
 
35886
 
 
35887
                        DUK_DDDPRINT("-> found, key is 'length', length special behavior");
 
35888
 
 
35889
                        h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
 
35890
                        DUK_ASSERT(h_val != NULL);
 
35891
                        if (push_value) {
 
35892
                                duk_push_number(ctx, (double) DUK_HSTRING_GET_CHARLEN(h_val));
 
35893
                        }
 
35894
                        out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;  /* E5 Section 15.5.5.1 */
 
35895
 
 
35896
                        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
 
35897
                        return 1;  /* cannot be arguments special */
 
35898
                }
 
35899
        } else if (DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) {
 
35900
                DUK_DDDPRINT("buffer object special property get for key: %!O, arr_idx: %d", key, arr_idx);
 
35901
 
 
35902
                if (arr_idx != DUK__NO_ARRAY_INDEX) {
 
35903
                        duk_hbuffer *h_val;
 
35904
 
 
35905
                        DUK_DDDPRINT("array index exists");
 
35906
 
 
35907
                        h_val = duk_hobject_get_internal_value_buffer(thr->heap, obj);
 
35908
                        DUK_ASSERT(h_val);
 
35909
                        /* SCANBUILD: h_val is known to be non-NULL but scan-build cannot
 
35910
                         * know it, so it produces NULL pointer dereference warnings for
 
35911
                         * 'h_val'.
 
35912
                         */
 
35913
 
 
35914
                        if (arr_idx < DUK_HBUFFER_GET_SIZE(h_val)) {
 
35915
                                DUK_DDDPRINT("-> found, array index inside buffer");
 
35916
                                if (push_value) {
 
35917
                                        duk_push_int(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h_val))[arr_idx]);
 
35918
                                }
 
35919
                                out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
 
35920
                                                  DUK_PROPDESC_FLAG_ENUMERABLE |
 
35921
                                                  DUK_PROPDESC_FLAG_VIRTUAL;
 
35922
 
 
35923
                                DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
 
35924
                                return 1;  /* cannot be e.g. arguments special, since special 'traits' are mutually exclusive */
 
35925
                        } else {
 
35926
                                /* index is above internal buffer length -> property is fully normal */
 
35927
                                DUK_DDDPRINT("array index outside buffer -> normal property");
 
35928
                        }
 
35929
                } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
35930
                        duk_hbuffer *h_val;
 
35931
 
 
35932
                        DUK_DDDPRINT("-> found, key is 'length', length special behavior");
 
35933
 
 
35934
                        /* XXX: buffer length should be writable and have special behavior
 
35935
                         * like arrays.  For now, make it read-only and use explicit methods
 
35936
                         * to operate on buffer length.
 
35937
                         */
 
35938
 
 
35939
                        h_val = duk_hobject_get_internal_value_buffer(thr->heap, obj);
 
35940
                        DUK_ASSERT(h_val != NULL);
 
35941
                        if (push_value) {
 
35942
                                duk_push_number(ctx, (double) DUK_HBUFFER_GET_SIZE(h_val));
 
35943
                        }
 
35944
                        out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
 
35945
 
 
35946
                        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
 
35947
                        return 1;  /* cannot be arguments special */
 
35948
                }
 
35949
        } else if (DUK_HOBJECT_HAS_SPECIAL_DUKFUNC(obj)) {
 
35950
                DUK_DDDPRINT("duktape/c object special property get for key: %!O, arr_idx: %d", key, arr_idx);
 
35951
 
 
35952
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
35953
                        DUK_DDDPRINT("-> found, key is 'length', length special behavior");
 
35954
 
 
35955
                        if (push_value) {
 
35956
                                duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
 
35957
                                duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
 
35958
                        }
 
35959
                        out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;  /* not enumerable */
 
35960
 
 
35961
                        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj));
 
35962
                        return 1;  /* cannot be arguments special */
 
35963
                }
 
35964
        }
 
35965
 
 
35966
        /* Array properties have special behavior but they are concrete,
 
35967
         * so no special handling here.
 
35968
         *
 
35969
         * Arguments special behavior (E5 Section 10.6, [[GetOwnProperty]]
 
35970
         * is only relevant as a post-check implemented below; hence no
 
35971
         * check here.
 
35972
         */
 
35973
 
 
35974
        /*
 
35975
         *  Not found as concrete or virtual
 
35976
         */
 
35977
 
 
35978
        DUK_DDDPRINT("-> not found (virtual, entry part, or array part)");
 
35979
        return 0;
 
35980
 
 
35981
        /*
 
35982
         *  Found
 
35983
         *
 
35984
         *  Arguments object has special post-processing, see E5 Section 10.6,
 
35985
         *  description of [[GetOwnProperty]] variant for arguments.
 
35986
         */
 
35987
 
 
35988
 prop_found:
 
35989
        DUK_DDDPRINT("-> property found, checking for arguments special post-behavior");
 
35990
 
 
35991
        /* Notes:
 
35992
         *  - only numbered indices are relevant, so arr_idx fast reject is good
 
35993
         *    (this is valid unless there are more than 4**32-1 arguments).
 
35994
         *  - since variable lookup has no side effects, this can be skipped if
 
35995
         *    push_value == 0.
 
35996
         */
 
35997
 
 
35998
        if (DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj) &&
 
35999
            arr_idx != DUK__NO_ARRAY_INDEX &&
 
36000
            push_value) {
 
36001
                duk_propdesc temp_desc;
 
36002
 
 
36003
                /* Magically bound variable cannot be an accessor.  However,
 
36004
                 * there may be an accessor property (or a plain property) in
 
36005
                 * place with magic behavior removed.  This happens e.g. when
 
36006
                 * a magic property is redefined with defineProperty().
 
36007
                 * Cannot assert for "not accessor" here.
 
36008
                 */
 
36009
 
 
36010
                /* replaces top of stack with new value if necessary */
 
36011
                DUK_ASSERT(push_value != 0);
 
36012
 
 
36013
                if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
 
36014
                        DUK_DDDPRINT("-> arguments special behavior overrides result: %!T -> %!T",
 
36015
                                     duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
36016
                        /* [... old_result result] -> [... result] */
 
36017
                        duk_remove(ctx, -2);
 
36018
                }
 
36019
        }
 
36020
 
 
36021
        return 1;
 
36022
}
 
36023
 
 
36024
static int duk__get_own_property_desc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, int push_value) {
 
36025
        DUK_ASSERT(thr != NULL);
 
36026
        DUK_ASSERT(obj != NULL);
 
36027
        DUK_ASSERT(key != NULL);
 
36028
        DUK_ASSERT(out_desc != NULL);
 
36029
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36030
 
 
36031
        return duk__get_own_property_desc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, push_value);
 
36032
}
 
36033
 
 
36034
/*
 
36035
 *  Ecmascript compliant [[GetProperty]](P), for internal use only.
 
36036
 *
 
36037
 *  If property is found:
 
36038
 *    - Fills descriptor fields to 'out_desc'
 
36039
 *    - If 'push_value' is non-zero, pushes a value related to the
 
36040
 *      property onto the stack ('undefined' for accessor properties).
 
36041
 *    - Returns non-zero
 
36042
 *
 
36043
 *  If property is not found:
 
36044
 *    - 'out_desc' is left in untouched state (possibly garbage)
 
36045
 *    - Nothing is pushed onto the stack (not even with push_value set)
 
36046
 *    - Returns zero
 
36047
 *
 
36048
 *  May cause arbitrary side effects and invalidate (most) duk_tval
 
36049
 *  pointers.
 
36050
 */
 
36051
 
 
36052
static int duk__get_property_desc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, int push_value) {
 
36053
        duk_hobject *curr;
 
36054
        duk_uint32_t arr_idx;
 
36055
        duk_uint32_t sanity;
 
36056
 
 
36057
        DUK_ASSERT(thr != NULL);
 
36058
        DUK_ASSERT(thr->heap != NULL);
 
36059
        DUK_ASSERT(obj != NULL);
 
36060
        DUK_ASSERT(key != NULL);
 
36061
        DUK_ASSERT(out_desc != NULL);
 
36062
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36063
 
 
36064
        arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
 
36065
 
 
36066
        DUK_DDDPRINT("duk__get_property_desc: thr=%p, obj=%p, key=%p, out_desc=%p, push_value=%d, arr_idx=%d (obj -> %!O, key -> %!O)",
 
36067
                     (void *) thr, (void *) obj, (void *) key, (void *) out_desc, push_value, arr_idx,
 
36068
                     (duk_heaphdr *) obj, (duk_heaphdr *) key);
 
36069
 
 
36070
        curr = obj;
 
36071
        DUK_ASSERT(curr != NULL);
 
36072
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
36073
        do {
 
36074
                if (duk__get_own_property_desc_raw(thr, curr, key, arr_idx, out_desc, push_value)) {
 
36075
                        /* stack contains value, 'out_desc' is set */
 
36076
                        return 1;
 
36077
                }
 
36078
 
 
36079
                /* not found in 'curr', next in prototype chain; impose max depth */
 
36080
                if (sanity-- == 0) {
 
36081
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "prototype chain max depth reached (loop?)");
 
36082
                }
 
36083
                curr = curr->prototype;
 
36084
        } while (curr);
 
36085
 
 
36086
        /* out_desc is left untouched (possibly garbage), caller must use return
 
36087
         * value to determine whether out_desc can be looked up
 
36088
         */
 
36089
 
 
36090
        return 0;
 
36091
}
 
36092
 
 
36093
/*
 
36094
 *  Shallow fast path checks for accessing array elements with numeric
 
36095
 *  indices.  The goal is to try to avoid coercing an array index to an
 
36096
 *  (interned) string for the most common lookups, in particular, for
 
36097
 *  standard Array objects.
 
36098
 *
 
36099
 *  Interning is avoided but only for a very narrow set of cases:
 
36100
 *    - Object has array part, index is within array allocation, and
 
36101
 *      value is not unused (= key exists)
 
36102
 *    - Object has no interfering special behavior (arguments or
 
36103
 *      string object special behaviors interfere, array special
 
36104
 *      behavior does not).
 
36105
 *
 
36106
 *  Current shortcoming: if key does not exist (even if it is within
 
36107
 *  the array allocation range) a slow path lookup with interning is
 
36108
 *  always required.  This can probably be fixed so that there is a
 
36109
 *  quick fast path for non-existent elements as well, at least for
 
36110
 *  standard Array objects.
 
36111
 */
 
36112
 
 
36113
#if 0  /* XXX: unused now */
 
36114
static duk_tval *duk__shallow_fast_path_array_check_u32(duk_hobject *obj, duk_uint32_t key_idx) {
 
36115
        duk_tval *tv;
 
36116
 
 
36117
        if ((!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) &&
 
36118
            (!DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj)) &&
 
36119
            (!DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) &&
 
36120
            (DUK_HOBJECT_HAS_ARRAY_PART(obj)) &&
 
36121
            (key_idx < obj->a_size)) {
 
36122
                /* technically required to check, but obj->a_size check covers this */
 
36123
                DUK_ASSERT(key_idx != 0xffffffffU);
 
36124
 
 
36125
                DUK_DDDPRINT("fast path attempt (key is an array index, no special "
 
36126
                             "string/arguments/buffer behavior, object has array part, key "
 
36127
                             "inside array size)"); 
 
36128
 
 
36129
                DUK_ASSERT(obj->a_size > 0);  /* true even for key_idx == 0 */
 
36130
                tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, key_idx);
 
36131
                if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
36132
                        DUK_DDDPRINT("-> fast path successful");
 
36133
                        return tv;
 
36134
                }
 
36135
 
 
36136
                /*
 
36137
                 *  Not found, fall back to slow path.
 
36138
                 *
 
36139
                 *  Note: this approach has the unfortunate side effect that accesses
 
36140
                 *  to undefined entries (or entries outside valid array range) cause
 
36141
                 *  a string intern operation.
 
36142
                 */
 
36143
 
 
36144
                DUK_DDDPRINT("fast path attempt failed, fall back to slow path");
 
36145
        }
 
36146
 
 
36147
        return NULL;
 
36148
}
 
36149
#endif
 
36150
 
 
36151
static duk_tval *duk__shallow_fast_path_array_check_tval(duk_hobject *obj, duk_tval *key_tv) {
 
36152
        duk_tval *tv;
 
36153
 
 
36154
        if (DUK_TVAL_IS_NUMBER(key_tv) &&
 
36155
            (!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) &&
 
36156
            (!DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(obj)) &&
 
36157
            (!DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(obj)) &&
 
36158
            (DUK_HOBJECT_HAS_ARRAY_PART(obj))) {
 
36159
                duk_uint32_t idx;
 
36160
 
 
36161
                DUK_DDDPRINT("fast path attempt (key is a number, no special string/arguments/buffer "
 
36162
                             "behavior, object has array part)");
 
36163
 
 
36164
                idx = duk__tval_number_to_arr_idx(key_tv);
 
36165
 
 
36166
                if (idx != DUK__NO_ARRAY_INDEX) {
 
36167
                        /* Note: idx is not necessarily a valid array index (0xffffffffU is not valid) */
 
36168
                        DUK_ASSERT_DISABLE(idx >= 0);  /* disabled because idx is duk_uint32_t so always true */
 
36169
                        DUK_ASSERT_DISABLE(idx <= 0xffffffffU);  /* same */
 
36170
 
 
36171
                        if (idx < obj->a_size) {
 
36172
                                /* technically required to check, but obj->a_size check covers this */
 
36173
                                DUK_ASSERT(idx != 0xffffffffU);
 
36174
 
 
36175
                                DUK_DDDPRINT("key is a valid array index and inside array part");
 
36176
                                tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, idx);
 
36177
                                if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
36178
                                        DUK_DDDPRINT("-> fast path successful");
 
36179
                                        return tv;
 
36180
                                }
 
36181
                        } else {
 
36182
                                DUK_DDDPRINT("key is outside array part");
 
36183
                        }
 
36184
                } else {
 
36185
                        DUK_DDDPRINT("key is not a valid array index");
 
36186
                }
 
36187
 
 
36188
                /*
 
36189
                 *  Not found in array part, use slow path.
 
36190
                 */
 
36191
 
 
36192
                DUK_DDDPRINT("fast path attempt failed, fall back to slow path");
 
36193
        }
 
36194
 
 
36195
        return NULL;
 
36196
}
 
36197
 
 
36198
/*
 
36199
 *  GETPROP: Ecmascript property read.
 
36200
 */
 
36201
 
 
36202
int duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
 
36203
        duk_context *ctx = (duk_context *) thr;
 
36204
        duk_tval tv_obj_copy;
 
36205
        duk_tval tv_key_copy;
 
36206
        duk_hobject *curr = NULL;
 
36207
        duk_hstring *key = NULL;
 
36208
        duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
 
36209
        duk_propdesc desc;
 
36210
        duk_uint32_t sanity;
 
36211
 
 
36212
        DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
 
36213
                     (void *) thr, (void *) tv_obj, (void *) tv_key, tv_obj, tv_key);
 
36214
 
 
36215
        DUK_ASSERT(ctx != NULL);
 
36216
        DUK_ASSERT(thr != NULL);
 
36217
        DUK_ASSERT(thr->heap != NULL);
 
36218
        DUK_ASSERT(tv_obj != NULL);
 
36219
        DUK_ASSERT(tv_key != NULL);
 
36220
 
 
36221
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36222
 
 
36223
        /*
 
36224
         *  Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
 
36225
         *  them being invalidated by a valstack resize.
 
36226
         *
 
36227
         *  XXX: this is now an overkill for many fast paths.  Rework this
 
36228
         *  to be faster (although switching to a valstack discipline might
 
36229
         *  be a better solution overall).
 
36230
         */
 
36231
 
 
36232
        DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
 
36233
        DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
 
36234
        tv_obj = &tv_obj_copy;
 
36235
        tv_key = &tv_key_copy;
 
36236
 
 
36237
        /*
 
36238
         *  Coercion and fast path processing
 
36239
         */
 
36240
 
 
36241
        switch (DUK_TVAL_GET_TAG(tv_obj)) {
 
36242
        case DUK_TAG_UNDEFINED:
 
36243
        case DUK_TAG_NULL: {
 
36244
                /* Note: unconditional throw */
 
36245
                DUK_DDDPRINT("base object is undefined or null -> reject");
 
36246
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid base reference for property read");
 
36247
                return 0;
 
36248
        }
 
36249
 
 
36250
        case DUK_TAG_BOOLEAN: {
 
36251
                DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype");
 
36252
                curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
 
36253
                break;
 
36254
        }
 
36255
 
 
36256
        case DUK_TAG_STRING: {
 
36257
                duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
 
36258
                duk_int_t pop_count;
 
36259
 
 
36260
                if (DUK_TVAL_IS_NUMBER(tv_key)) {
 
36261
                        arr_idx = duk__tval_number_to_arr_idx(tv_key);
 
36262
                        DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %d", (int) arr_idx);
 
36263
                        pop_count = 0;
 
36264
                } else {
 
36265
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36266
                        DUK_ASSERT(key != NULL);
 
36267
                        DUK_DDDPRINT("base object string, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
36268
                        pop_count = 1;
 
36269
                }
 
36270
 
 
36271
                if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
36272
                    arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
 
36273
                        duk_pop_n(ctx, pop_count);
 
36274
                        duk_push_hstring(ctx, h);
 
36275
                        duk_substring(ctx, -1, arr_idx, arr_idx + 1);  /* [str] -> [substr] */
 
36276
 
 
36277
                        DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
 
36278
                                     "after coercion -> return char)",
 
36279
                                     duk_get_tval(ctx, -1));
 
36280
                        return 1;
 
36281
                }
 
36282
 
 
36283
                if (pop_count == 0) {
 
36284
                        /* This is a pretty awkward control flow, but we need to recheck the
 
36285
                         * key coercion here.
 
36286
                         */
 
36287
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36288
                        DUK_ASSERT(key != NULL);
 
36289
                        DUK_DDDPRINT("base object string, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
36290
                }
 
36291
 
 
36292
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
36293
                        duk_pop(ctx);  /* [key] -> [] */
 
36294
                        duk_push_number(ctx, (double) DUK_HSTRING_GET_CHARLEN(h));  /* [] -> [res] */
 
36295
 
 
36296
                        DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
 
36297
                                     "return string length)",
 
36298
                                     duk_get_tval(ctx, -1));
 
36299
                        return 1;
 
36300
                }
 
36301
                DUK_DDDPRINT("base object is a string, start lookup from string prototype");
 
36302
                curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
 
36303
                goto lookup;  /* avoid double coercion */
 
36304
        }
 
36305
 
 
36306
        case DUK_TAG_OBJECT: {
 
36307
                duk_tval *tmp;
 
36308
 
 
36309
                curr = DUK_TVAL_GET_OBJECT(tv_obj);
 
36310
                DUK_ASSERT(curr != NULL);
 
36311
 
 
36312
                tmp = duk__shallow_fast_path_array_check_tval(curr, tv_key);
 
36313
                if (tmp) {
 
36314
                        duk_push_tval(ctx, tmp);
 
36315
 
 
36316
                        DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
 
36317
                                     "fast path)",
 
36318
                                     duk_get_tval(ctx, -1));
 
36319
                        return 1;
 
36320
                }
 
36321
 
 
36322
                if (DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(curr)) {
 
36323
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36324
                        DUK_ASSERT(key != NULL);
 
36325
 
 
36326
                        if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
 
36327
                                DUK_DDDPRINT("-> %!T (base is object with arguments special behavior, "
 
36328
                                             "key matches magically bound property -> skip standard "
 
36329
                                             "Get with replacement value)",
 
36330
                                             duk_get_tval(ctx, -1));
 
36331
 
 
36332
                                /* no need for 'caller' post-check, because 'key' must be an array index */
 
36333
 
 
36334
                                duk_remove(ctx, -2);  /* [key result] -> [result] */
 
36335
                                return 1;
 
36336
                        }
 
36337
 
 
36338
                        goto lookup;  /* avoid double coercion */
 
36339
                }
 
36340
                break;
 
36341
        }
 
36342
 
 
36343
        /* Buffer has virtual properties similar to string, but indexed values
 
36344
         * are numbers, not 1-byte buffers/strings which would perform badly.
 
36345
         */
 
36346
        case DUK_TAG_BUFFER: {
 
36347
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
 
36348
                duk_int_t pop_count;
 
36349
 
 
36350
                /*
 
36351
                 *  Because buffer values are often looped over, a number fast path
 
36352
                 *  is important.
 
36353
                 */
 
36354
 
 
36355
                if (DUK_TVAL_IS_NUMBER(tv_key)) {
 
36356
                        arr_idx = duk__tval_number_to_arr_idx(tv_key);
 
36357
                        DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %d", (int) arr_idx);
 
36358
                        pop_count = 0;
 
36359
                } else {
 
36360
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36361
                        DUK_ASSERT(key != NULL);
 
36362
                        DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
36363
                        pop_count = 1;
 
36364
                }
 
36365
 
 
36366
                if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
36367
                    arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
 
36368
                        duk_pop_n(ctx, pop_count);
 
36369
                        duk_push_int(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h))[arr_idx]);
 
36370
 
 
36371
                        DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
 
36372
                                     "after coercion -> return byte as number)",
 
36373
                                     duk_get_tval(ctx, -1));
 
36374
                        return 1;
 
36375
                }
 
36376
 
 
36377
                if (pop_count == 0) {
 
36378
                        /* This is a pretty awkward control flow, but we need to recheck the
 
36379
                         * key coercion here.
 
36380
                         */
 
36381
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36382
                        DUK_ASSERT(key != NULL);
 
36383
                        DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
36384
                }
 
36385
 
 
36386
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
36387
                        duk_pop(ctx);  /* [key] -> [] */
 
36388
                        duk_push_number(ctx, (double) DUK_HBUFFER_GET_SIZE(h));  /* [] -> [res] */
 
36389
 
 
36390
                        DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' after coercion -> "
 
36391
                                     "return buffer length)",
 
36392
                                     duk_get_tval(ctx, -1));
 
36393
                        return 1;
 
36394
                }
 
36395
 
 
36396
                DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype");
 
36397
                curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
 
36398
                goto lookup;  /* avoid double coercion */
 
36399
        }
 
36400
 
 
36401
        case DUK_TAG_POINTER: {
 
36402
                DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype");
 
36403
                curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
 
36404
                break;
 
36405
        }
 
36406
 
 
36407
        default: {
 
36408
                /* number */
 
36409
                DUK_DDDPRINT("base object is a number, start lookup from number prototype");
 
36410
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
 
36411
                curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
 
36412
                break;
 
36413
        }
 
36414
        }
 
36415
 
 
36416
        /* key coercion (unless already coerced above) */
 
36417
        DUK_ASSERT(key == NULL);
 
36418
        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
36419
        DUK_ASSERT(key != NULL);
 
36420
 
 
36421
        /*
 
36422
         *  Property lookup
 
36423
         */
 
36424
 
 
36425
 lookup:
 
36426
        /* [key] (coerced) */
 
36427
        DUK_ASSERT(curr != NULL);
 
36428
        DUK_ASSERT(key != NULL);
 
36429
 
 
36430
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
36431
        do {
 
36432
                /* 1 = push_value */
 
36433
                if (!duk__get_own_property_desc_raw(thr, curr, key, arr_idx, &desc, 1)) {
 
36434
                        goto next_in_chain;
 
36435
                }
 
36436
 
 
36437
                if (desc.get != NULL) {
 
36438
                        /* accessor with defined getter */
 
36439
                        DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
 
36440
 
 
36441
                        duk_pop(ctx);                     /* [key undefined] -> [key] */
 
36442
                        duk_push_hobject(ctx, desc.get);
 
36443
                        duk_push_tval(ctx, tv_obj);       /* note: original, uncoerced base */
 
36444
                        duk_call_method(ctx, 0);          /* [key getter this] -> [key retval] */
 
36445
                } else {
 
36446
                        /* [key value] or [key undefined] */
 
36447
 
 
36448
                        /* data property or accessor without getter */
 
36449
                        DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
 
36450
                                   (desc.get == NULL));
 
36451
 
 
36452
                        /* if accessor without getter, return value is undefined */
 
36453
                        DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
 
36454
                                   duk_is_undefined(ctx, -1));
 
36455
 
 
36456
                        /* Note: for an accessor without getter, falling through to
 
36457
                         * check for "caller" special behavior is unnecessary as
 
36458
                         * "undefined" will never activate the behavior.  But it does
 
36459
                         * no harm, so we'll do it anyway.
 
36460
                         */
 
36461
                }
 
36462
 
 
36463
                goto found;  /* [key result] */
 
36464
 
 
36465
         next_in_chain:
 
36466
                if (sanity-- == 0) {
 
36467
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "prototype chain max depth reached (loop?)");
 
36468
                }
 
36469
                curr = curr->prototype;
 
36470
        } while (curr);
 
36471
 
 
36472
        /*
 
36473
         *  Not found
 
36474
         */
 
36475
 
 
36476
        duk_to_undefined(ctx, -1);  /* [key] -> [undefined] (default value) */
 
36477
 
 
36478
        DUK_DDDPRINT("-> %!T (not found)",
 
36479
                     duk_get_tval(ctx, -1));
 
36480
        return 0;
 
36481
 
 
36482
        /*
 
36483
         *  Found; post-processing (Function and arguments objects)
 
36484
         */
 
36485
 
 
36486
 found:
 
36487
        /* [key result] */
 
36488
 
 
36489
#if !defined(DUK_USE_FUNC_NONSTD_CALLER_PROPERTY)
 
36490
        /* This special behavior is disabled when the non-standard 'caller' property
 
36491
         * is enabled, as it conflicts with the free use of 'caller'.
 
36492
         */
 
36493
        if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
 
36494
            DUK_TVAL_IS_OBJECT(tv_obj)) {
 
36495
                duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
 
36496
 
 
36497
                if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
 
36498
                    DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(orig)) {
 
36499
                        duk_hobject *h;
 
36500
 
 
36501
                        /* FIXME: is this behavior desired for bound functions too?
 
36502
                         * E5.1 Section 15.3.4.5 step 6 seems to indicate so, while
 
36503
                         * E5.1 Section 15.3.5.4 "NOTE" indicates that bound functions
 
36504
                         * have a default [[Get]] method.
 
36505
                         *
 
36506
                         * Also, must the value Function object be a non-bound function?
 
36507
                         */
 
36508
 
 
36509
                        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(orig));
 
36510
 
 
36511
                        h = duk_get_hobject(ctx, -1);  /* NULL if not an object */
 
36512
                        if (h &&
 
36513
                            DUK_HOBJECT_IS_FUNCTION(h) &&
 
36514
                            DUK_HOBJECT_HAS_STRICT(h)) {
 
36515
                                /* XXX: sufficient to check 'strict', assert for 'is function' */
 
36516
                                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "attempt to read strict 'caller'");
 
36517
                        }
 
36518
                }
 
36519
        }
 
36520
#endif   /* !DUK_USE_FUNC_NONSTD_CALLER_PROPERTY */
 
36521
 
 
36522
        duk_remove(ctx, -2);  /* [key result] -> [result] */
 
36523
 
 
36524
        DUK_DDDPRINT("-> %!T (found)",
 
36525
                     duk_get_tval(ctx, -1));
 
36526
        return 1;
 
36527
}
 
36528
 
 
36529
/*
 
36530
 *  HASPROP: Ecmascript property existence check ("in" operator).
 
36531
 *
 
36532
 *  Interestingly, the 'in' operator does not do any coercion of
 
36533
 *  the target object.
 
36534
 */
 
36535
 
 
36536
int duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
 
36537
        duk_context *ctx = (duk_context *) thr;
 
36538
        duk_hobject *obj;
 
36539
        duk_hstring *key;
 
36540
        int rc;
 
36541
        duk_propdesc dummy;
 
36542
 
 
36543
        DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
 
36544
                     (void *) thr, (void *) tv_obj, (void *) tv_key, tv_obj, tv_key);
 
36545
 
 
36546
        DUK_ASSERT(thr != NULL);
 
36547
        DUK_ASSERT(thr->heap != NULL);
 
36548
        DUK_ASSERT(tv_obj != NULL);
 
36549
        DUK_ASSERT(tv_key != NULL);
 
36550
 
 
36551
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36552
 
 
36553
        /* No need to make a copy of the input duk_tvals here. */
 
36554
 
 
36555
        if (!DUK_TVAL_IS_OBJECT(tv_obj)) {
 
36556
                /* Note: unconditional throw */
 
36557
                DUK_DDDPRINT("base object is not an object -> reject");
 
36558
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid base reference for property existence check");
 
36559
        }
 
36560
        obj = DUK_TVAL_GET_OBJECT(tv_obj);
 
36561
        DUK_ASSERT(obj != NULL);
 
36562
 
 
36563
        duk_push_tval(ctx, tv_key);
 
36564
        duk_to_string(ctx, -1);
 
36565
        key = duk_get_hstring(ctx, -1);
 
36566
        DUK_ASSERT(key != NULL);
 
36567
 
 
36568
        /* XXX: inline into a prototype walking loop? */
 
36569
 
 
36570
        rc = duk__get_property_desc(thr, obj, key, &dummy, 0);  /* push_value = 0 */
 
36571
 
 
36572
        duk_pop(ctx);  /* [key] -> [] */
 
36573
        return rc;
 
36574
}
 
36575
 
 
36576
/*
 
36577
 *  HASPROP variant used internally.
 
36578
 *
 
36579
 *  This primitive must never throw an error, caller's rely on this.
 
36580
 */
 
36581
 
 
36582
int duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
 
36583
        duk_propdesc dummy;
 
36584
 
 
36585
        DUK_ASSERT(thr != NULL);
 
36586
        DUK_ASSERT(thr->heap != NULL);
 
36587
        DUK_ASSERT(obj != NULL);
 
36588
        DUK_ASSERT(key != NULL);
 
36589
 
 
36590
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36591
 
 
36592
        return duk__get_property_desc(thr, obj, key, &dummy, 0);  /* push_value = 0 */
 
36593
}
 
36594
 
 
36595
 
 
36596
/*
 
36597
 *  Helper: handle Array object 'length' write which automatically
 
36598
 *  deletes properties, see E5 Section 15.4.5.1, step 3.  This is
 
36599
 *  quite tricky to get right.
 
36600
 *
 
36601
 *  Used by duk_hobject_putprop().
 
36602
 */
 
36603
 
 
36604
static duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc) {
 
36605
        int rc;
 
36606
        duk_tval *tv;
 
36607
        duk_uint32_t res;
 
36608
 
 
36609
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36610
 
 
36611
        /* FIXME: this assumption is actually invalid, because e.g. Array.prototype.push()
 
36612
         * can create an array whose length is above 2**32.
 
36613
         */
 
36614
 
 
36615
        /* Call only for objects with array special behavior, as we assume
 
36616
         * that the length property always exists, and always contains a
 
36617
         * valid number value (in unsigned 32-bit range).
 
36618
         */
 
36619
 
 
36620
        rc = duk__get_own_property_desc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, temp_desc, 0);
 
36621
        DUK_UNREF(rc);
 
36622
        DUK_ASSERT(rc != 0);  /* arrays MUST have a 'length' property */
 
36623
        DUK_ASSERT(temp_desc->e_idx >= 0);
 
36624
 
 
36625
        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, temp_desc->e_idx);
 
36626
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));  /* array 'length' is always a number, as we coerce it */
 
36627
        DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) >= 0.0);
 
36628
        DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (double) 0xffffffffU);
 
36629
        res = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
 
36630
        DUK_ASSERT((double) res == DUK_TVAL_GET_NUMBER(tv));
 
36631
 
 
36632
        return res;
 
36633
}
 
36634
 
 
36635
static duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) {
 
36636
        duk_context *ctx = (duk_context *) thr;
 
36637
        duk_uint32_t res;
 
36638
 
 
36639
        /* Input value should be on stack top and will be coerced and
 
36640
         * left on stack top.
 
36641
         */
 
36642
 
 
36643
        /* FIXME: coerce in_val to new_len, check that this is correct */
 
36644
        res = ((duk_uint32_t) duk_to_number(ctx, -1)) & 0xffffffffU;
 
36645
        if (res != duk_get_number(ctx, -1)) {
 
36646
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "invalid array length");
 
36647
        }
 
36648
        return res;
 
36649
}
 
36650
 
 
36651
/* Delete elements required by a smaller length, taking into account
 
36652
 * potentially non-configurable elements.  Returns non-zero if all
 
36653
 * elements could be deleted, and zero if all or some elements could
 
36654
 * not be deleted.  Also writes final "target length" to 'out_result_len'.
 
36655
 * This is the length value that should go into the 'length' property
 
36656
 * (must be set by the caller).  Never throws an error.
 
36657
 */
 
36658
static int duk__handle_put_array_length_smaller(duk_hthread *thr,
 
36659
                                                duk_hobject *obj,
 
36660
                                                duk_uint32_t old_len,
 
36661
                                                duk_uint32_t new_len,
 
36662
                                                duk_uint32_t *out_result_len) {
 
36663
        duk_uint32_t target_len;
 
36664
        duk_uint32_t i;
 
36665
        duk_uint32_t arr_idx;
 
36666
        duk_hstring *key;
 
36667
        duk_tval *tv;
 
36668
        duk_tval tv_tmp;
 
36669
        int rc;
 
36670
 
 
36671
        DUK_DDDPRINT("new array length smaller than old (%d -> %d), "
 
36672
                     "probably need to remove elements",
 
36673
                     old_len, new_len);
 
36674
 
 
36675
        /*
 
36676
         *  New length is smaller than old length, need to delete properties above
 
36677
         *  the new length.
 
36678
         *
 
36679
         *  If array part exists, this is straightforward: array entries cannot
 
36680
         *  be non-configurable so this is guaranteed to work.
 
36681
         *
 
36682
         *  If array part does not exist, array-indexed values are scattered
 
36683
         *  in the entry part, and some may not be configurable (preventing length
 
36684
         *  from becoming lower than their index + 1).  To handle the algorithm
 
36685
         *  in E5 Section 15.4.5.1, step l correctly, we scan the entire property
 
36686
         *  set twice.
 
36687
         */
 
36688
 
 
36689
        DUK_ASSERT(thr != NULL);
 
36690
        DUK_ASSERT(obj != NULL);
 
36691
        DUK_ASSERT(new_len < old_len);
 
36692
        DUK_ASSERT(out_result_len != NULL);
 
36693
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36694
 
 
36695
        if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
 
36696
                /*
 
36697
                 *  All defined array-indexed properties are in the array part
 
36698
                 *  (we assume the array part is comprehensive), and all array
 
36699
                 *  entries are writable, configurable, and enumerable.  Thus,
 
36700
                 *  nothing can prevent array entries from being deleted.
 
36701
                 */
 
36702
 
 
36703
                DUK_DDDPRINT("have array part, easy case");
 
36704
 
 
36705
                if (old_len < obj->a_size) {
 
36706
                        /* XXX: assertion that entries >= old_len are already unused */
 
36707
                        i = old_len;
 
36708
                } else {
 
36709
                        i = obj->a_size;
 
36710
                }
 
36711
                DUK_ASSERT(i <= obj->a_size);
 
36712
 
 
36713
                while (i > new_len) {
 
36714
                        i--;
 
36715
                        tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, i);
 
36716
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
36717
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
36718
                        DUK_TVAL_DECREF(thr, &tv_tmp);
 
36719
                }
 
36720
 
 
36721
                *out_result_len = new_len;
 
36722
                return 1;
 
36723
        } else {
 
36724
                /*
 
36725
                 *  Entries part is a bit more complex
 
36726
                 */
 
36727
 
 
36728
                /* stage 1: find highest preventing non-configurable entry (if any) */
 
36729
 
 
36730
                DUK_DDDPRINT("no array part, slow case");
 
36731
 
 
36732
                DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
 
36733
                             "(highest preventing non-configurable entry (if any))");
 
36734
 
 
36735
                target_len = new_len;
 
36736
                for (i = 0; i < obj->e_used; i++) {
 
36737
                        key = DUK_HOBJECT_E_GET_KEY(obj, i);
 
36738
                        if (!key) {
 
36739
                                DUK_DDDPRINT("skip entry index %d: null key", i);
 
36740
                                continue;
 
36741
                        }
 
36742
                        if (!DUK_HSTRING_HAS_ARRIDX(key)) {
 
36743
                                DUK_DDDPRINT("skip entry index %d: key not an array index", i);
 
36744
                                continue;
 
36745
                        }
 
36746
 
 
36747
                        DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key));  /* XXX: macro checks for array index flag, which is unnecessary here */
 
36748
                        arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
 
36749
                        DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
 
36750
                        DUK_ASSERT(arr_idx < old_len);  /* consistency requires this */
 
36751
 
 
36752
                        if (arr_idx < new_len) {
 
36753
                                DUK_DDDPRINT("skip entry index %d: key is array index %d, below new_len", i, arr_idx);
 
36754
                                continue;
 
36755
                        }
 
36756
                        if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i)) {
 
36757
                                DUK_DDDPRINT("skip entry index %d: key is a relevant array index %d, but configurable", i, arr_idx);
 
36758
                                continue;
 
36759
                        }
 
36760
 
 
36761
                        /* relevant array index is non-configurable, blocks write */
 
36762
                        if (arr_idx >= target_len) {
 
36763
                                DUK_DDDPRINT("entry at index %d has arr_idx %d, is not configurable, "
 
36764
                                             "update target_len %d -> %d",
 
36765
                                             i, arr_idx, target_len, arr_idx + 1);
 
36766
                                target_len = arr_idx + 1;
 
36767
                        }
 
36768
                }
 
36769
 
 
36770
                /* stage 2: delete configurable entries above target length */
 
36771
 
 
36772
                DUK_DDDPRINT("old_len=%d, new_len=%d, target_len=%d",
 
36773
                             old_len, new_len, target_len);
 
36774
 
 
36775
                DUK_DDDPRINT("array length write, no array part, stage 2: remove "
 
36776
                             "entries >= target_len");
 
36777
 
 
36778
                for (i = 0; i < obj->e_used; i++) {
 
36779
                        key = DUK_HOBJECT_E_GET_KEY(obj, i);
 
36780
                        if (!key) {
 
36781
                                DUK_DDDPRINT("skip entry index %d: null key", i);
 
36782
                                continue;
 
36783
                        }
 
36784
                        if (!DUK_HSTRING_HAS_ARRIDX(key)) {
 
36785
                                DUK_DDDPRINT("skip entry index %d: key not an array index", i);
 
36786
                                continue;
 
36787
                        }
 
36788
 
 
36789
                        DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key));  /* XXX: macro checks for array index flag, which is unnecessary here */
 
36790
                        arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
 
36791
                        DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
 
36792
                        DUK_ASSERT(arr_idx < old_len);  /* consistency requires this */
 
36793
 
 
36794
                        if (arr_idx < target_len) {
 
36795
                                DUK_DDDPRINT("skip entry index %d: key is array index %d, below target_len", i, arr_idx);
 
36796
                                continue;
 
36797
                        }
 
36798
                        DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i));  /* stage 1 guarantees */
 
36799
 
 
36800
                        DUK_DDDPRINT("delete entry index %d: key is array index %d", i, arr_idx);
 
36801
 
 
36802
                        /*
 
36803
                         *  Slow delete, but we don't care as we're already in a very slow path.
 
36804
                         *  The delete always succeeds: key has no special behavior, property
 
36805
                         *  is configurable, and no resize occurs.
 
36806
                         */
 
36807
                        rc = duk_hobject_delprop_raw(thr, obj, key, 0);
 
36808
                        DUK_UNREF(rc);
 
36809
                        DUK_ASSERT(rc != 0);
 
36810
                }
 
36811
 
 
36812
                /* stage 3: update length (done by caller), decide return code */
 
36813
 
 
36814
                DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)");
 
36815
 
 
36816
                *out_result_len = target_len;
 
36817
 
 
36818
                if (target_len == new_len) {
 
36819
                        DUK_DDDPRINT("target_len matches new_len, return success");
 
36820
                        return 1;
 
36821
                }
 
36822
                DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
 
36823
                             "full length adjustment), return error");
 
36824
                return 0;
 
36825
        }
 
36826
 
 
36827
        DUK_UNREACHABLE();
 
36828
}
 
36829
 
 
36830
/* FIXME: is valstack top best place for argument? */
 
36831
static int duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
 
36832
        duk_context *ctx = (duk_context *) thr;
 
36833
        duk_propdesc desc;
 
36834
        duk_uint32_t old_len;
 
36835
        duk_uint32_t new_len;
 
36836
        duk_uint32_t result_len;
 
36837
        duk_tval *tv;
 
36838
        int rc;
 
36839
 
 
36840
        DUK_DDDPRINT("handling a put operation to array 'length' special property, "
 
36841
                     "new val: %!T",
 
36842
                     duk_get_tval(ctx, -1));
 
36843
 
 
36844
        DUK_ASSERT(thr != NULL);
 
36845
        DUK_ASSERT(ctx != NULL);
 
36846
        DUK_ASSERT(obj != NULL);
 
36847
 
 
36848
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36849
 
 
36850
        DUK_ASSERT(duk_is_valid_index(ctx, -1));
 
36851
 
 
36852
        /*
 
36853
         *  Get old and new length
 
36854
         */
 
36855
 
 
36856
        old_len = duk__get_old_array_length(thr, obj, &desc);
 
36857
        duk_dup(ctx, -1);  /* [in_val in_val] */
 
36858
        new_len = duk__to_new_array_length_checked(thr);
 
36859
        duk_pop(ctx);  /* [in_val in_val] -> [in_val] */
 
36860
        DUK_DDDPRINT("old_len=%d, new_len=%d", old_len, new_len);
 
36861
 
 
36862
        /*
 
36863
         *  Writability check
 
36864
         */
 
36865
 
 
36866
        if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
36867
                DUK_DDDPRINT("length is not writable, fail");
 
36868
                return 0;
 
36869
        }
 
36870
 
 
36871
        /*
 
36872
         *  New length not lower than old length => no changes needed
 
36873
         *  (not even array allocation).
 
36874
         */
 
36875
 
 
36876
        if (new_len >= old_len) {
 
36877
                DUK_DDDPRINT("new length is higher than old length, just update length, no deletions");
 
36878
 
 
36879
                DUK_ASSERT(desc.e_idx >= 0);
 
36880
                DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, desc.e_idx));
 
36881
                tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, desc.e_idx);
 
36882
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
36883
                DUK_TVAL_SET_NUMBER(tv, (double) new_len);  /* no decref needed for a number */
 
36884
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
36885
                return 1;
 
36886
        }
 
36887
 
 
36888
        DUK_DDDPRINT("new length is lower than old length, probably must delete entries");
 
36889
 
 
36890
        /*
 
36891
         *  New length lower than old length => delete elements, then
 
36892
         *  update length.
 
36893
         *
 
36894
         *  Note: even though a bunch of elements have been deleted, the 'desc' is
 
36895
         *  still valid as properties haven't been resized (and entries compacted).
 
36896
         */
 
36897
 
 
36898
        rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, &result_len);
 
36899
        DUK_ASSERT(result_len >= new_len && result_len <= old_len);
 
36900
 
 
36901
        DUK_ASSERT(desc.e_idx >= 0);
 
36902
        DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, desc.e_idx));
 
36903
        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, desc.e_idx);
 
36904
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
36905
        DUK_TVAL_SET_NUMBER(tv, (double) result_len);  /* no decref needed for a number */
 
36906
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
36907
 
 
36908
        /*
 
36909
         *  FIXME: shrink array allocation or entries compaction here?
 
36910
         */
 
36911
 
 
36912
        return rc;
 
36913
}
 
36914
 
 
36915
/*
 
36916
 *  PUTPROP: Ecmascript property write.
 
36917
 *
 
36918
 *  Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
 
36919
 *  success and 0 to indicate failure (assuming throw is not set).
 
36920
 *
 
36921
 *  This is an extremely tricky function.  Some examples:
 
36922
 *
 
36923
 *    * Currently a decref may trigger a GC, which may compact an object's
 
36924
 *      property allocation.  Consequently, any entry indices (e_idx) will
 
36925
 *      be potentially invalidated by a decref.
 
36926
 *
 
36927
 *    * Special behaviors (strings, arrays, arguments object) require,
 
36928
 *      among other things:
 
36929
 *
 
36930
 *      - Preprocessing before and postprocessing after an actual property
 
36931
 *        write.  For example, array index write requires pre-checking the
 
36932
 *        array 'length' property for access control, and may require an
 
36933
 *        array 'length' update after the actual write has succeeded (but
 
36934
 *        not if it fails).
 
36935
 *
 
36936
 *      - Deletion of multiple entries, as a result of array 'length' write.
 
36937
 *
 
36938
 *    * Input values are taken as pointers which may point to the valstack.
 
36939
 *      If valstack is resized because of the put (this may happen at least
 
36940
 *      when the array part is abandoned), the pointers can be invalidated.
 
36941
 *      (We currently make a copy of all of the input values to avoid issues.)
 
36942
 */
 
36943
 
 
36944
int duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, int throw_flag) {
 
36945
        duk_context *ctx = (duk_context *) thr;
 
36946
        duk_tval tv_obj_copy;
 
36947
        duk_tval tv_key_copy;
 
36948
        duk_tval tv_val_copy;
 
36949
        duk_hobject *orig = NULL;  /* NULL if tv_obj is primitive */
 
36950
        duk_hobject *curr;
 
36951
        duk_hstring *key = NULL;
 
36952
        duk_propdesc desc;
 
36953
        duk_tval *tv;
 
36954
        duk_uint32_t arr_idx;
 
36955
        int rc;
 
36956
        int e_idx;
 
36957
        duk_uint32_t sanity;
 
36958
        duk_uint32_t new_array_length = 0;  /* 0 = no update */
 
36959
 
 
36960
        DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%d "
 
36961
                     "(obj -> %!T, key -> %!T, val -> %!T)",
 
36962
                     (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
 
36963
                     (int) throw_flag, tv_obj, tv_key, tv_val);
 
36964
 
 
36965
        DUK_ASSERT(thr != NULL);
 
36966
        DUK_ASSERT(thr->heap != NULL);
 
36967
        DUK_ASSERT(ctx != NULL);
 
36968
        DUK_ASSERT(tv_obj != NULL);
 
36969
        DUK_ASSERT(tv_key != NULL);
 
36970
        DUK_ASSERT(tv_val != NULL);
 
36971
 
 
36972
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
36973
 
 
36974
        /*
 
36975
         *  Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
 
36976
         *  them being invalidated by a valstack resize.
 
36977
         *
 
36978
         *  XXX: this is an overkill for some paths, so optimize this later
 
36979
         *  (or maybe switch to a stack arguments model entirely).
 
36980
         */
 
36981
 
 
36982
        DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
 
36983
        DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
 
36984
        DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
 
36985
        tv_obj = &tv_obj_copy;
 
36986
        tv_key = &tv_key_copy;
 
36987
        tv_val = &tv_val_copy;
 
36988
 
 
36989
        /*
 
36990
         *  Coercion and fast path processing.
 
36991
         */
 
36992
 
 
36993
        switch (DUK_TVAL_GET_TAG(tv_obj)) {
 
36994
        case DUK_TAG_UNDEFINED:
 
36995
        case DUK_TAG_NULL: {
 
36996
                /* Note: unconditional throw */
 
36997
                DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)", tv_obj);
 
36998
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid base reference for property write");
 
36999
                return 0;
 
37000
        }
 
37001
 
 
37002
        case DUK_TAG_BOOLEAN: {
 
37003
                DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype");
 
37004
                curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
 
37005
                break;
 
37006
        }
 
37007
 
 
37008
        case DUK_TAG_STRING: {
 
37009
                duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
 
37010
 
 
37011
                /*
 
37012
                 *  Note: currently no fast path for array index writes.
 
37013
                 *  They won't be possible anyway as strings are immutable.
 
37014
                 */
 
37015
 
 
37016
                DUK_ASSERT(key == NULL);
 
37017
                arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
37018
                DUK_ASSERT(key != NULL);
 
37019
 
 
37020
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
37021
                        goto fail_not_writable;
 
37022
                }
 
37023
 
 
37024
                if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37025
                    arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
 
37026
                        goto fail_not_writable;
 
37027
                }
 
37028
 
 
37029
                DUK_DDDPRINT("base object is a string, start lookup from string prototype");
 
37030
                curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
 
37031
                goto lookup;  /* avoid double coercion */
 
37032
        }
 
37033
 
 
37034
        case DUK_TAG_OBJECT: {
 
37035
                /* Note: no fast paths for property put now */
 
37036
                orig = DUK_TVAL_GET_OBJECT(tv_obj);
 
37037
                DUK_ASSERT(orig != NULL);
 
37038
                curr = orig;
 
37039
                break;
 
37040
        }
 
37041
 
 
37042
        case DUK_TAG_BUFFER: {
 
37043
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
 
37044
                duk_int_t pop_count = 0;
 
37045
 
 
37046
                /*
 
37047
                 *  Because buffer values may be looped over and read/written
 
37048
                 *  from, an array index fast path is important.
 
37049
                 */
 
37050
 
 
37051
                if (DUK_TVAL_IS_NUMBER(tv_key)) {
 
37052
                        arr_idx = duk__tval_number_to_arr_idx(tv_key);
 
37053
                        DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %d", (int) arr_idx);
 
37054
                        pop_count = 0;
 
37055
                } else {
 
37056
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
37057
                        DUK_ASSERT(key != NULL);
 
37058
                        DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
37059
                        pop_count = 1;
 
37060
                }
 
37061
 
 
37062
                if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37063
                    arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
 
37064
                        duk_uint8_t *data;
 
37065
                        DUK_DDDPRINT("writing to buffer data at index %d", (int) arr_idx);
 
37066
                        data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
 
37067
                        duk_push_tval(ctx, tv_val);
 
37068
                        data[arr_idx] = (duk_uint8_t) duk_to_number(ctx, -1);
 
37069
                        pop_count++;
 
37070
                        duk_pop_n(ctx, pop_count);
 
37071
                        DUK_DDDPRINT("result: success (buffer data write)");
 
37072
                        return 1;
 
37073
                }
 
37074
 
 
37075
                if (pop_count == 0) {
 
37076
                        /* This is a pretty awkward control flow, but we need to recheck the
 
37077
                         * key coercion here.
 
37078
                         */
 
37079
                        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
37080
                        DUK_ASSERT(key != NULL);
 
37081
                        DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after coercion key is %!T, arr_idx %d", duk_get_tval(ctx, -1), (int) arr_idx);
 
37082
                }
 
37083
 
 
37084
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
37085
                        goto fail_not_writable;
 
37086
                }
 
37087
 
 
37088
                DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype");
 
37089
                curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
 
37090
                goto lookup;  /* avoid double coercion */
 
37091
        }
 
37092
 
 
37093
        case DUK_TAG_POINTER: {
 
37094
                DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype");
 
37095
                curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
 
37096
                break;
 
37097
        }
 
37098
 
 
37099
        default: {
 
37100
                /* number */
 
37101
                DUK_DDDPRINT("base object is a number, start lookup from number prototype");
 
37102
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
 
37103
                curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
 
37104
                break;
 
37105
        }
 
37106
        }
 
37107
 
 
37108
        DUK_ASSERT(key == NULL);
 
37109
        arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
 
37110
        DUK_ASSERT(key != NULL);
 
37111
 
 
37112
 lookup:
 
37113
 
 
37114
        /*
 
37115
         *  Check whether the property already exists in the prototype chain.
 
37116
         *  Note that the actual write goes into the original base object
 
37117
         *  (except if an accessor property captures the write).
 
37118
         */
 
37119
 
 
37120
        /* [key] */
 
37121
 
 
37122
        DUK_ASSERT(curr != NULL);
 
37123
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
37124
        do {
 
37125
                /* 0 = don't push current value */
 
37126
                if (!duk__get_own_property_desc_raw(thr, curr, key, arr_idx, &desc, 0)) {
 
37127
                        goto next_in_chain;
 
37128
                }
 
37129
 
 
37130
                if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
37131
                        /*
 
37132
                         *  Found existing accessor property (own or inherited).
 
37133
                         *  Call setter with 'this' set to orig, and value as the only argument.
 
37134
                         *
 
37135
                         *  Note: no special arguments object behavior, because [[Put]] never
 
37136
                         *  calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
 
37137
                         */
 
37138
 
 
37139
                        duk_hobject *setter;
 
37140
 
 
37141
                        DUK_DDPRINT("put to an own or inherited accessor, calling setter");
 
37142
 
 
37143
                        setter = DUK_HOBJECT_E_GET_VALUE_SETTER(curr, desc.e_idx);
 
37144
                        if (!setter) {
 
37145
                                goto fail_no_setter;
 
37146
                        }
 
37147
                        duk_push_hobject(ctx, setter);
 
37148
                        duk_push_tval(ctx, tv_obj);  /* note: original, uncoerced base */
 
37149
                        duk_push_tval(ctx, tv_val);  /* [key setter this val] */
 
37150
                        duk_call_method(ctx, 1);     /* -> [key retval] */
 
37151
                        duk_pop(ctx);                /* ignore retval -> [key] */
 
37152
                        goto success_no_arguments_special;
 
37153
                }
 
37154
 
 
37155
                if (orig == NULL) {
 
37156
                        /*
 
37157
                         *  Found existing own or inherited plain property, but original
 
37158
                         *  base is a primitive value.
 
37159
                         */
 
37160
                        DUK_DDPRINT("attempt to create a new property in a primitive base object");
 
37161
                        goto fail_base_primitive;
 
37162
                }
 
37163
 
 
37164
                if (curr != orig) {
 
37165
                        /*
 
37166
                         *  Found existing inherited plain property.
 
37167
                         *  Do an access control check, and if OK, write
 
37168
                         *  new property to 'orig'.
 
37169
                         */
 
37170
                        if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
 
37171
                                DUK_DDPRINT("found existing inherited plain property, but original object is not extensible");
 
37172
                                goto fail_not_extensible;
 
37173
                        }
 
37174
                        if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
37175
                                DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable");
 
37176
                                goto fail_not_writable;
 
37177
                        }
 
37178
                        DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable");
 
37179
                        goto create_new;
 
37180
                } else {
 
37181
                        /*
 
37182
                         *  Found existing own (non-inherited) plain property.
 
37183
                         *  Do an access control check and update in place.
 
37184
                         */
 
37185
 
 
37186
                        if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
37187
                                DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable");
 
37188
                                goto fail_not_writable;
 
37189
                        }
 
37190
                        if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
 
37191
                                DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable");
 
37192
                                if (DUK_HOBJECT_HAS_SPECIAL_BUFFEROBJ(curr)) {
 
37193
                                        duk_hbuffer *h;
 
37194
 
 
37195
                                        DUK_DDPRINT("writable virtual property is in buffer object");
 
37196
                                        h = duk_hobject_get_internal_value_buffer(thr->heap, curr);
 
37197
                                        DUK_ASSERT(h != NULL);
 
37198
 
 
37199
                                        if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37200
                                            arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
 
37201
                                                duk_uint8_t *data;
 
37202
                                                DUK_DDDPRINT("writing to buffer data at index %d", (int) arr_idx);
 
37203
                                                data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(h);
 
37204
                                                duk_push_tval(ctx, tv_val);
 
37205
                                                data[arr_idx] = (duk_uint8_t) duk_to_number(ctx, -1);
 
37206
                                                duk_pop(ctx);
 
37207
                                                goto success_no_arguments_special;
 
37208
                                        }
 
37209
                                }
 
37210
 
 
37211
                                goto fail_internal;  /* should not happen */
 
37212
                        }
 
37213
                        DUK_DDPRINT("put to existing own plain property, property is writable");
 
37214
                        goto update_old;
 
37215
                }
 
37216
                DUK_UNREACHABLE();
 
37217
 
 
37218
         next_in_chain:
 
37219
                if (sanity-- == 0) {
 
37220
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "prototype chain max depth reached (loop?)");
 
37221
                }
 
37222
                curr = curr->prototype;
 
37223
        } while (curr);
 
37224
 
 
37225
        /*
 
37226
         *  Property not found in prototype chain.
 
37227
         */
 
37228
 
 
37229
        DUK_DDDPRINT("property not found in prototype chain");
 
37230
 
 
37231
        if (orig == NULL) {
 
37232
                DUK_DDPRINT("attempt to create a new property in a primitive base object");
 
37233
                goto fail_base_primitive;
 
37234
        }
 
37235
 
 
37236
        if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
 
37237
                DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible");
 
37238
                goto fail_not_extensible;
 
37239
        }
 
37240
 
 
37241
        goto create_new;
 
37242
 
 
37243
 update_old:
 
37244
 
 
37245
        /*
 
37246
         *  Update an existing property of the base object.
 
37247
         */
 
37248
 
 
37249
        /* [key] */
 
37250
 
 
37251
        DUK_DDDPRINT("update an existing property of the original object");
 
37252
 
 
37253
        DUK_ASSERT(orig != NULL);
 
37254
 
 
37255
        /* Although there are writable virtual properties (e.g. plain buffer
 
37256
         * and buffer object number indices), they are handled before we come
 
37257
         * here.
 
37258
         */
 
37259
        DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
 
37260
        DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
 
37261
 
 
37262
        if (DUK_HOBJECT_HAS_SPECIAL_ARRAY(orig) &&
 
37263
            key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
37264
                /*
 
37265
                 *  Write to 'length' of an array is a very complex case
 
37266
                 *  handled in a helper which updates both the array elements
 
37267
                 *  and writes the new 'length'.  The write may result in an
 
37268
                 *  unconditional RangeError or a partial write (indicated
 
37269
                 *  by a return code).
 
37270
                 *
 
37271
                 *  Note: the helper has an unnecessary writability check
 
37272
                 *  for 'length', we already know it is writable.
 
37273
                 */
 
37274
 
 
37275
                DUK_DDDPRINT("writing existing 'length' property to array special, invoke complex helper");
 
37276
 
 
37277
                /* FIXME: the helper currently assumes stack top contains new
 
37278
                 * 'length' value and the whole calling convention is not very
 
37279
                 * compatible with what we need.
 
37280
                 */
 
37281
 
 
37282
                duk_push_tval(ctx, tv_val);  /* [key val] */
 
37283
                rc = duk__handle_put_array_length(thr, orig);
 
37284
                duk_pop(ctx);  /* [key val] -> [key] */
 
37285
                if (!rc) {
 
37286
                        goto fail_array_length_partial;
 
37287
                }
 
37288
 
 
37289
                /* key is 'length', cannot match argument special behavior */
 
37290
                goto success_no_arguments_special;
 
37291
        }
 
37292
 
 
37293
        if (desc.e_idx >= 0) {
 
37294
                duk_tval tv_tmp;
 
37295
 
 
37296
                tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(orig, desc.e_idx);
 
37297
                DUK_DDDPRINT("previous entry value: %!iT", tv);
 
37298
                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
37299
                DUK_TVAL_SET_TVAL(tv, tv_val);
 
37300
                DUK_TVAL_INCREF(thr, tv);
 
37301
                DUK_TVAL_DECREF(thr, &tv_tmp);  /* note: may trigger gc and props compaction, must be last */
 
37302
                /* don't touch property attributes or hash part */
 
37303
                DUK_DDPRINT("put to an existing entry at index %d -> new value %!iT", desc.e_idx, tv);
 
37304
        } else {
 
37305
                /* Note: array entries are always writable, so the writability check
 
37306
                 * above is pointless for them.  The check could be avoided with some
 
37307
                 * refactoring but is probably not worth it.
 
37308
                 */
 
37309
                duk_tval tv_tmp;
 
37310
 
 
37311
                DUK_ASSERT(desc.a_idx >= 0);
 
37312
                tv = DUK_HOBJECT_A_GET_VALUE_PTR(orig, desc.a_idx);
 
37313
                DUK_DDDPRINT("previous array value: %!iT", tv);
 
37314
                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
37315
                DUK_TVAL_SET_TVAL(tv, tv_val);
 
37316
                DUK_TVAL_INCREF(thr, tv);
 
37317
                DUK_TVAL_DECREF(thr, &tv_tmp);  /* note: may trigger gc and props compaction, must be last */
 
37318
                DUK_DDPRINT("put to an existing array entry at index %d -> new value %!iT", desc.a_idx, tv);
 
37319
        }
 
37320
 
 
37321
        /* Regardless of whether property is found in entry or array part,
 
37322
         * it may have arguments special behavior (array indices may reside
 
37323
         * in entry part for abandoned / non-existent array parts).
 
37324
         */
 
37325
        goto success_with_arguments_special;
 
37326
 
 
37327
 create_new:
 
37328
 
 
37329
        /*
 
37330
         *  Create a new property in the original object.
 
37331
         *
 
37332
         *  Special properties need to be reconsidered here from a write
 
37333
         *  perspective (not just property attributes perspective).
 
37334
         *  However, the property does not exist in the object already,
 
37335
         *  so this limits the kind of special properties that apply.
 
37336
         */
 
37337
 
 
37338
        /* [key] */
 
37339
 
 
37340
        DUK_DDDPRINT("create new property to original object");
 
37341
 
 
37342
        DUK_ASSERT(orig != NULL);
 
37343
 
 
37344
        /* Not possible because array object 'length' is present
 
37345
         * from its creation and cannot be deleted, and is thus
 
37346
         * caught as an existing property above.
 
37347
         */
 
37348
        DUK_ASSERT(!(DUK_HOBJECT_HAS_SPECIAL_ARRAY(orig) &&
 
37349
                     key == DUK_HTHREAD_STRING_LENGTH(thr)));
 
37350
 
 
37351
        if (DUK_HOBJECT_HAS_SPECIAL_ARRAY(orig) &&
 
37352
            arr_idx != DUK__NO_ARRAY_INDEX) {
 
37353
                /* automatic length update */
 
37354
                duk_uint32_t old_len;
 
37355
 
 
37356
                old_len = duk__get_old_array_length(thr, orig, &desc);
 
37357
 
 
37358
                if (arr_idx >= old_len) {
 
37359
                        DUK_DDDPRINT("write new array entry requires length update "
 
37360
                                     "(arr_idx=%d, old_len=%d)",
 
37361
                                     arr_idx, old_len);
 
37362
 
 
37363
                        if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
37364
                                DUK_DDPRINT("attempt to extend array, but array 'length' is not writable");
 
37365
                                goto fail_not_writable;
 
37366
                        }
 
37367
 
 
37368
                        /* Note: actual update happens once write has been completed
 
37369
                         * without error below.  The write should always succeed
 
37370
                         * from a specification viewpoint, but we may e.g. run out
 
37371
                         * of memory.  It's safer in this order.
 
37372
                         */
 
37373
 
 
37374
                        DUK_ASSERT(arr_idx != 0xffffffffU);
 
37375
                        new_array_length = arr_idx + 1;  /* flag for later write */
 
37376
                } else {
 
37377
                        DUK_DDDPRINT("write new array entry does not require length update "
 
37378
                                     "(arr_idx=%d, old_len=%d)",
 
37379
                                     arr_idx, old_len);
 
37380
                }
 
37381
        }
 
37382
 
 
37383
 /* write_to_array_part: */
 
37384
 
 
37385
        /*
 
37386
         *  Write to array part?
 
37387
         *
 
37388
         *  Note: array abandonding requires a property resize which uses
 
37389
         *  'rechecks' valstack for temporaries and may cause any existing
 
37390
         *  valstack pointers to be invalidated.  To protect against this,
 
37391
         *  tv_obj, tv_key, and tv_val are copies of the original inputs.
 
37392
         */
 
37393
 
 
37394
        if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37395
            DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
 
37396
                if (arr_idx < orig->a_size) {
 
37397
                        goto no_array_growth;
 
37398
                }
 
37399
 
 
37400
                /*
 
37401
                 *  Array needs to grow, but we don't want it becoming too sparse.
 
37402
                 *  If it were to become sparse, abandon array part, moving all
 
37403
                 *  array entries into the entries part (for good).
 
37404
                 *
 
37405
                 *  Since we don't keep track of actual density (used vs. size) of
 
37406
                 *  the array part, we need to estimate somehow.  The check is made
 
37407
                 *  in two parts:
 
37408
                 *
 
37409
                 *    - Check whether the resize need is small compared to the
 
37410
                 *      current size (relatively); if so, resize without further
 
37411
                 *      checking (essentially we assume that the original part is
 
37412
                 *      "dense" so that the result would be dense enough).
 
37413
                 *
 
37414
                 *    - Otherwise, compute the resize using an actual density
 
37415
                 *      measurement based on counting the used array entries.
 
37416
                 */
 
37417
 
 
37418
                DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
 
37419
                             "fast resize without abandon check (arr_idx=%d, old_size=%d)",
 
37420
                             arr_idx, orig->a_size);
 
37421
 
 
37422
                if (duk__abandon_array_slow_check_required(arr_idx, orig->a_size)) {
 
37423
                        duk_uint32_t old_used;
 
37424
                        duk_uint32_t old_size;
 
37425
 
 
37426
                        DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon");
 
37427
 
 
37428
                        duk__compute_a_stats(orig, &old_used, &old_size);
 
37429
 
 
37430
                        DUK_DDDPRINT("abandon check, array stats: old_used=%d, old_size=%d, arr_idx=%d",
 
37431
                                     old_used, old_size, arr_idx);
 
37432
 
 
37433
                        /* Note: intentionally use approximations to shave a few instructions:
 
37434
                         *   a_used = old_used  (accurate: old_used + 1)
 
37435
                         *   a_size = arr_idx   (accurate: arr_idx + 1)
 
37436
                         */
 
37437
                        if (duk__abandon_array_density_check(old_used, arr_idx)) {
 
37438
                                DUK_DDPRINT("write to new array entry beyond current length, "
 
37439
                                            "decided to abandon array part (would become too sparse)");
 
37440
 
 
37441
                                /* abandoning requires a props allocation resize and
 
37442
                                 * 'rechecks' the valstack, invalidating any existing
 
37443
                                 * valstack value pointers!
 
37444
                                 */
 
37445
                                duk__abandon_array_checked(thr, orig);
 
37446
                                DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
 
37447
 
 
37448
                                goto write_to_entry_part;
 
37449
                        }
 
37450
 
 
37451
                        DUK_DDDPRINT("=> decided to keep array part");
 
37452
                } else {
 
37453
                        DUK_DDDPRINT("=> fast resize is OK");
 
37454
                }
 
37455
 
 
37456
                DUK_DDPRINT("write to new array entry beyond current length, "
 
37457
                            "decided to extend current allocation");
 
37458
 
 
37459
                duk__grow_props_for_array_item(thr, orig, arr_idx);
 
37460
 
 
37461
         no_array_growth:
 
37462
 
 
37463
                /* Note: assume array part is comprehensive, so that either
 
37464
                 * the write goes to the array part, or we've abandoned the
 
37465
                 * array above (and will not come here).
 
37466
                 */
 
37467
 
 
37468
                DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
 
37469
                DUK_ASSERT(arr_idx < orig->a_size);
 
37470
 
 
37471
                tv = DUK_HOBJECT_A_GET_VALUE_PTR(orig, arr_idx);
 
37472
                /* prev value must be unused, no decref */
 
37473
                DUK_ASSERT(DUK_TVAL_IS_UNDEFINED_UNUSED(tv));
 
37474
                DUK_TVAL_SET_TVAL(tv, tv_val);
 
37475
                DUK_TVAL_INCREF(thr, tv);
 
37476
                DUK_DDPRINT("put to new array entry: %d -> %!T", (int) arr_idx, tv);
 
37477
 
 
37478
                /* Note: array part values are [[Writable]], [[Enumerable]],
 
37479
                 * and [[Configurable]] which matches the required attributes
 
37480
                 * here.
 
37481
                 */
 
37482
                goto entry_updated;
 
37483
        }
 
37484
 
 
37485
 write_to_entry_part:
 
37486
 
 
37487
        /*
 
37488
         *  Write to entry part
 
37489
         */
 
37490
 
 
37491
        /* entry allocation updates hash part and increases the key
 
37492
         * refcount; may need a props allocation resize but doesn't
 
37493
         * 'recheck' the valstack.
 
37494
         */
 
37495
        e_idx = duk__alloc_entry_checked(thr, orig, key);
 
37496
        DUK_ASSERT(e_idx >= 0);
 
37497
 
 
37498
        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(orig, e_idx);
 
37499
        /* prev value can be garbage, no decref */
 
37500
        DUK_TVAL_SET_TVAL(tv, tv_val);
 
37501
        DUK_TVAL_INCREF(thr, tv);
 
37502
        DUK_HOBJECT_E_SET_FLAGS(orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
 
37503
        goto entry_updated;
 
37504
 
 
37505
 entry_updated:
 
37506
 
 
37507
        /*
 
37508
         *  Possible pending array length update, which must only be done
 
37509
         *  if the actual entry write succeeded.
 
37510
         */     
 
37511
 
 
37512
        if (new_array_length > 0) {
 
37513
                /*
 
37514
                 *  Note: zero works as a "no update" marker because the new length
 
37515
                 *  can never be zero after a new property is written.
 
37516
                 *
 
37517
                 *  Note: must re-lookup because calls above (e.g. duk__alloc_entry_checked())
 
37518
                 *  may realloc and compact properties and hence change e_idx.
 
37519
                 */
 
37520
 
 
37521
                DUK_DDDPRINT("write successful, pending array length update to: %d", new_array_length);
 
37522
 
 
37523
                rc = duk__get_own_property_desc_raw(thr, orig, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &desc, 0);
 
37524
                DUK_UNREF(rc);
 
37525
                DUK_ASSERT(rc != 0);
 
37526
                DUK_ASSERT(desc.e_idx >= 0);
 
37527
 
 
37528
                tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(orig, desc.e_idx);
 
37529
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
37530
                DUK_TVAL_SET_NUMBER(tv, (double) new_array_length);  /* no need for decref/incref because value is a number */
 
37531
        }
 
37532
 
 
37533
        /*
 
37534
         *  Arguments special behavior not possible for new properties: all
 
37535
         *  magically bound properties are initially present in the arguments
 
37536
         *  object, and if they are deleted, the binding is also removed from
 
37537
         *  parameter map.
 
37538
         */
 
37539
 
 
37540
        goto success_no_arguments_special;
 
37541
 
 
37542
 success_with_arguments_special:
 
37543
 
 
37544
        /*
 
37545
         *  Arguments objects have special [[DefineOwnProperty]] which updates
 
37546
         *  the internal 'map' of arguments for writes to currently mapped
 
37547
         *  arguments.  More conretely, writes to mapped arguments generate
 
37548
         *  a write to a bound variable.
 
37549
         *
 
37550
         *  The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
 
37551
         *  data properties and new properties, but not for existing accessors.
 
37552
         *  Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
 
37553
         *  have a Desc with 'Value' (and possibly other properties too), and
 
37554
         *  we end up in step 5.b.i.
 
37555
         */
 
37556
 
 
37557
        if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37558
            DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(orig)) {
 
37559
                /* Note: only numbered indices are relevant, so arr_idx fast reject
 
37560
                 * is good (this is valid unless there are more than 4**32-1 arguments).
 
37561
                 */
 
37562
 
 
37563
                DUK_DDDPRINT("putprop successful, arguments special behavior needed");
 
37564
 
 
37565
                /* Note: we can reuse 'desc' here */
 
37566
 
 
37567
                /* FIXME: top of stack must contain value, which helper doesn't touch,
 
37568
                 * rework to use tv_val directly?
 
37569
                 */
 
37570
 
 
37571
                duk_push_tval(ctx, tv_val);
 
37572
                (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
 
37573
                duk_pop(ctx);
 
37574
        }
 
37575
        /* fall thru */
 
37576
 
 
37577
 success_no_arguments_special:
 
37578
        /* shared exit path now */
 
37579
        DUK_DDDPRINT("result: success");
 
37580
        duk_pop(ctx);  /* remove key */
 
37581
        return 1;
 
37582
 
 
37583
 fail_base_primitive:
 
37584
        DUK_DDDPRINT("result: error, base primitive");
 
37585
        if (throw_flag) {
 
37586
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "non-object base reference");
 
37587
        }
 
37588
        duk_pop(ctx);  /* remove key */
 
37589
        return 0;
 
37590
 
 
37591
 fail_not_extensible:
 
37592
        DUK_DDDPRINT("result: error, not extensible");
 
37593
        if (throw_flag) {
 
37594
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "object not extensible");
 
37595
        }
 
37596
        duk_pop(ctx);  /* remove key */
 
37597
        return 0;
 
37598
        
 
37599
 fail_not_writable:
 
37600
        DUK_DDDPRINT("result: error, not writable");
 
37601
        if (throw_flag) {
 
37602
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "property not writable");
 
37603
        }
 
37604
        duk_pop(ctx);  /* remove key */
 
37605
        return 0;
 
37606
 
 
37607
 fail_array_length_partial:
 
37608
        DUK_DDDPRINT("result: error, array length write only partially successful");
 
37609
        if (throw_flag) {
 
37610
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "array length write failed");
 
37611
        }
 
37612
        duk_pop(ctx);  /* remove key */
 
37613
        return 0;
 
37614
 
 
37615
 fail_no_setter:
 
37616
        DUK_DDDPRINT("result: error, accessor property without setter");
 
37617
        if (throw_flag) {
 
37618
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "undefined setter for accessor");
 
37619
        }
 
37620
        duk_pop(ctx);  /* remove key */
 
37621
        return 0;
 
37622
 
 
37623
 fail_internal:
 
37624
        DUK_DDDPRINT("result: error, internal");
 
37625
        if (throw_flag) {
 
37626
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "internal error");
 
37627
        }
 
37628
        duk_pop(ctx);  /* remove key */
 
37629
        return 0;
 
37630
}
 
37631
 
 
37632
/*
 
37633
 *  Ecmascript compliant [[Delete]](P, Throw).
 
37634
 */
 
37635
 
 
37636
int duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, int throw_flag) {
 
37637
        duk_propdesc desc;
 
37638
        duk_tval *tv;
 
37639
        duk_tval tv_tmp;
 
37640
        duk_uint32_t arr_idx;
 
37641
 
 
37642
        DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%d (obj -> %!O, key -> %!O)",
 
37643
                     (void *) thr, (void *) obj, (void *) key, (int) throw_flag,
 
37644
                     (duk_heaphdr *) obj, (duk_heaphdr *) key);
 
37645
 
 
37646
        DUK_ASSERT(thr != NULL);
 
37647
        DUK_ASSERT(thr->heap != NULL);
 
37648
        DUK_ASSERT(obj != NULL);
 
37649
        DUK_ASSERT(key != NULL);
 
37650
 
 
37651
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
37652
 
 
37653
        arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
 
37654
 
 
37655
        /* 0 = don't push current value */
 
37656
        if (!duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &desc, 0)) {
 
37657
                DUK_DDDPRINT("property not found, succeed always");
 
37658
                goto success;
 
37659
        }
 
37660
 
 
37661
        if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0) {
 
37662
                goto fail_not_configurable;
 
37663
        }
 
37664
 
 
37665
        /* currently there are no deletable virtual properties */
 
37666
        DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
 
37667
 
 
37668
        if (desc.a_idx >= 0) {
 
37669
                DUK_ASSERT(desc.e_idx < 0);
 
37670
 
 
37671
                tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, desc.a_idx);
 
37672
                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
37673
                DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
37674
                DUK_TVAL_DECREF(thr, &tv_tmp);
 
37675
                goto success;
 
37676
        } else {
 
37677
                DUK_ASSERT(desc.a_idx < 0);
 
37678
 
 
37679
                /* remove hash entry (no decref) */
 
37680
                if (desc.h_idx >= 0) {
 
37681
                        duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(obj);
 
37682
 
 
37683
                        DUK_DDDPRINT("removing hash entry at h_idx %d", desc.h_idx);
 
37684
                        DUK_ASSERT(obj->h_size > 0);
 
37685
                        DUK_ASSERT((duk_size_t) desc.h_idx < obj->h_size);  /* FIXME: h_idx typing */
 
37686
                        h_base[desc.h_idx] = DUK__HASH_DELETED;
 
37687
                } else {
 
37688
                        DUK_ASSERT(obj->h_size == 0);
 
37689
                }
 
37690
 
 
37691
                /* remove value */
 
37692
                DUK_DDDPRINT("before removing value, e_idx %d, key %p, key at slot %p",
 
37693
                             desc.e_idx, key, DUK_HOBJECT_E_GET_KEY(obj, desc.e_idx));
 
37694
                DUK_DDDPRINT("removing value at e_idx %d", desc.e_idx);
 
37695
                if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, desc.e_idx)) {
 
37696
                        duk_hobject *tmp;
 
37697
 
 
37698
                        tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(obj, desc.e_idx);
 
37699
                        DUK_HOBJECT_E_SET_VALUE_GETTER(obj, desc.e_idx, NULL);
 
37700
                        DUK_UNREF(tmp);
 
37701
                        DUK_HOBJECT_DECREF(thr, tmp);
 
37702
 
 
37703
                        tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(obj, desc.e_idx);
 
37704
                        DUK_HOBJECT_E_SET_VALUE_SETTER(obj, desc.e_idx, NULL);
 
37705
                        DUK_UNREF(tmp);
 
37706
                        DUK_HOBJECT_DECREF(thr, tmp);
 
37707
                } else {
 
37708
                        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, desc.e_idx);
 
37709
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
37710
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
37711
                        DUK_TVAL_DECREF(thr, &tv_tmp);
 
37712
                }
 
37713
                /* this is not strictly necessary because if key == NULL, value MUST be ignored */
 
37714
                DUK_HOBJECT_E_SET_FLAGS(obj, desc.e_idx, 0);
 
37715
                DUK_TVAL_SET_UNDEFINED_UNUSED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, desc.e_idx));
 
37716
 
 
37717
                /* remove key */
 
37718
                DUK_DDDPRINT("before removing key, e_idx %d, key %p, key at slot %p",
 
37719
                             desc.e_idx, key, DUK_HOBJECT_E_GET_KEY(obj, desc.e_idx));
 
37720
                DUK_DDDPRINT("removing key at e_idx %d", desc.e_idx);
 
37721
                DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(obj, desc.e_idx));
 
37722
                DUK_HOBJECT_E_SET_KEY(obj, desc.e_idx, NULL);
 
37723
                DUK_HSTRING_DECREF(thr, key);
 
37724
                goto success;
 
37725
        }
 
37726
 
 
37727
        DUK_UNREACHABLE();
 
37728
        
 
37729
 success:
 
37730
        /*
 
37731
         *  Argument special [[Delete]] behavior (E5 Section 10.6) is
 
37732
         *  a post-check, keeping arguments internal 'map' in sync with
 
37733
         *  any successful deletes (note that property does not need to
 
37734
         *  exist for delete to 'succeed').
 
37735
         *
 
37736
         *  Delete key from 'map'.  Since 'map' only contains array index
 
37737
         *  keys, we can use arr_idx for a fast skip.
 
37738
         */
 
37739
 
 
37740
        DUK_DDDPRINT("delete successful, check for arguments special behavior");
 
37741
 
 
37742
        if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) {
 
37743
                /* Note: only numbered indices are relevant, so arr_idx fast reject
 
37744
                 * is good (this is valid unless there are more than 4**32-1 arguments).
 
37745
                 */
 
37746
 
 
37747
                DUK_DDDPRINT("delete successful, arguments special behavior needed");
 
37748
 
 
37749
                /* Note: we can reuse 'desc' here */
 
37750
                (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
 
37751
        }
 
37752
 
 
37753
        DUK_DDDPRINT("delete successful");
 
37754
        return 1;
 
37755
 
 
37756
 fail_not_configurable:
 
37757
        DUK_DDDPRINT("delete failed: property found, not configurable");
 
37758
 
 
37759
        if (throw_flag) {
 
37760
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "property not configurable");
 
37761
        }
 
37762
        return 0;
 
37763
}
 
37764
 
 
37765
 
 
37766
/*
 
37767
 *  DELPROP: Ecmascript property deletion.
 
37768
 */
 
37769
 
 
37770
int duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, int throw_flag) {
 
37771
        duk_context *ctx = (duk_context *) thr;
 
37772
        duk_hstring *key = NULL;
 
37773
        duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
 
37774
        int rc;
 
37775
 
 
37776
        DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
 
37777
                     (void *) thr, (void *) tv_obj, (void *) tv_key, tv_obj, tv_key);
 
37778
 
 
37779
        DUK_ASSERT(ctx != NULL);
 
37780
        DUK_ASSERT(thr != NULL);
 
37781
        DUK_ASSERT(thr->heap != NULL);
 
37782
        DUK_ASSERT(tv_obj != NULL);
 
37783
        DUK_ASSERT(tv_key != NULL);
 
37784
 
 
37785
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
37786
 
 
37787
        if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
 
37788
            DUK_TVAL_IS_NULL(tv_obj)) {
 
37789
                /* Note: unconditional throw */
 
37790
                DUK_DDDPRINT("base object is undefined or null -> reject");
 
37791
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid base reference for property delete");
 
37792
        }
 
37793
 
 
37794
        /* FIXME: because we need to do this, just take args through stack? */
 
37795
        duk_push_tval(ctx, tv_obj);
 
37796
        duk_push_tval(ctx, tv_key);
 
37797
 
 
37798
        duk_to_string(ctx, -1);
 
37799
        key = duk_get_hstring(ctx, -1);
 
37800
        DUK_ASSERT(key != NULL);
 
37801
 
 
37802
        tv_obj = duk_get_tval(ctx, -2);
 
37803
        if (DUK_TVAL_IS_OBJECT(tv_obj)) {
 
37804
                duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
 
37805
 
 
37806
                DUK_ASSERT(obj != NULL);
 
37807
 
 
37808
                rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag);
 
37809
 
 
37810
                duk_pop_2(ctx);  /* [obj key] -> [] */
 
37811
                return rc;
 
37812
        } else if (DUK_TVAL_IS_STRING(tv_obj)) {
 
37813
                duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
 
37814
 
 
37815
                DUK_ASSERT(h != NULL);
 
37816
 
 
37817
                if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
37818
                        goto fail_not_configurable;
 
37819
                }
 
37820
 
 
37821
                arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
 
37822
 
 
37823
                if (arr_idx != DUK__NO_ARRAY_INDEX &&
 
37824
                    arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
 
37825
                        goto fail_not_configurable;
 
37826
                }
 
37827
        }
 
37828
 
 
37829
        /* string without matching properties, or any other primitive base */
 
37830
 
 
37831
        duk_pop_2(ctx);  /* [obj key] -> [] */
 
37832
        return 1;
 
37833
 
 
37834
 fail_not_configurable:
 
37835
        if (throw_flag) {
 
37836
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "property not configurable");
 
37837
        }
 
37838
        return 0;
 
37839
}
 
37840
 
 
37841
/*
 
37842
 *  Internal helper to define a property with specific flags, ignoring
 
37843
 *  normal semantics such as extensibility, write protection etc.
 
37844
 *  Overwrites any existing value and attributes unless caller requests
 
37845
 *  that value only be updated if it doesn't already exists.  If target
 
37846
 *  has an array part, asserts that propflags are correct (WEC).
 
37847
 *
 
37848
 *  Does not support:
 
37849
 *    - virtual properties
 
37850
 *    - getter/setter properties
 
37851
 *    - array abandoning: if array part exists, it is always extended
 
37852
 *
 
37853
 *  Stack: [... in_val] -> []
 
37854
 *
 
37855
 *  Used for e.g. built-in initialization and environment record
 
37856
 *  operations.
 
37857
 */
 
37858
 
 
37859
void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_int_t flags) {
 
37860
        duk_context *ctx = (duk_context *) thr;
 
37861
        duk_propdesc desc;
 
37862
        duk_uint32_t arr_idx;
 
37863
        int e_idx;
 
37864
        duk_tval tv_tmp;
 
37865
        duk_tval *tv1 = NULL;
 
37866
        duk_tval *tv2 = NULL;
 
37867
        int propflags = flags & DUK_PROPDESC_FLAGS_MASK;  /* mask out flags not actually stored */
 
37868
 
 
37869
        DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02x, val=%!T",
 
37870
                     (void *) thr, obj, key, flags, duk_get_tval(ctx, -1));
 
37871
 
 
37872
        DUK_ASSERT(thr != NULL);
 
37873
        DUK_ASSERT(thr->heap != NULL);
 
37874
        DUK_ASSERT(obj != NULL);
 
37875
        DUK_ASSERT(key != NULL);
 
37876
 
 
37877
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
37878
        DUK_ASSERT(duk_is_valid_index(ctx, -1));  /* contains value */
 
37879
 
 
37880
        arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
 
37881
 
 
37882
        if (duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &desc, 0)) {  /* push_value = 0 */
 
37883
                if (desc.e_idx >= 0) {
 
37884
                        if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
 
37885
                                DUK_DDDPRINT("property already exists in the entry part -> skip as requested");
 
37886
                                goto skip_write;
 
37887
                        }
 
37888
                        DUK_DDDPRINT("property already exists in the entry part -> update value and attributes");
 
37889
                        DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, desc.e_idx));
 
37890
 
 
37891
                        DUK_HOBJECT_E_SET_FLAGS(obj, desc.e_idx, propflags);
 
37892
                        tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, desc.e_idx);
 
37893
                } else if (desc.a_idx >= 0) {
 
37894
                        if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
 
37895
                                DUK_DDDPRINT("property already exists in the array part -> skip as requested");
 
37896
                                goto skip_write;
 
37897
                        }
 
37898
                        DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)");
 
37899
                        DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
 
37900
 
 
37901
                        tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(obj, desc.a_idx);
 
37902
                } else {
 
37903
                        if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
 
37904
                                DUK_DDDPRINT("property already exists but is virtual -> skip as requested");
 
37905
                                goto skip_write;
 
37906
                        }
 
37907
                        DUK_DDDPRINT("property already exists but is virtual -> failure");
 
37908
                        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "attempt to redefine virtual property");
 
37909
                        DUK_UNREACHABLE();
 
37910
                }
 
37911
 
 
37912
                goto write_value;
 
37913
        }
 
37914
 
 
37915
        if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
 
37916
                if (arr_idx != DUK__NO_ARRAY_INDEX) {
 
37917
                        DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)");
 
37918
                        DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
 
37919
 
 
37920
                        /* always grow the array, no sparse / abandon support here */
 
37921
                        if (arr_idx >= obj->a_size) {
 
37922
                                duk__grow_props_for_array_item(thr, obj, arr_idx);
 
37923
                        }
 
37924
 
 
37925
                        DUK_ASSERT(arr_idx < obj->a_size);
 
37926
                        tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(obj, arr_idx);
 
37927
                        goto write_value;                       
 
37928
                }
 
37929
        }
 
37930
 
 
37931
        DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes");
 
37932
        e_idx = duk__alloc_entry_checked(thr, obj, key);  /* increases key refcount */
 
37933
        DUK_ASSERT(e_idx >= 0);
 
37934
        DUK_HOBJECT_E_SET_FLAGS(obj, e_idx, propflags);
 
37935
        tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx);
 
37936
        /* new entry: previous value is garbage; set to undefined to share write_value */
 
37937
        DUK_TVAL_SET_UNDEFINED_ACTUAL(tv1);
 
37938
        goto write_value;
 
37939
 
 
37940
 write_value:
 
37941
        /* tv1 points to value storage */
 
37942
 
 
37943
        tv2 = duk_require_tval(ctx, -1);  /* late lookup, avoid side effects */
 
37944
        DUK_DDDPRINT("writing/updating value: %!T -> %!T", tv1, tv2);
 
37945
 
 
37946
        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
37947
        DUK_TVAL_SET_TVAL(tv1, tv2);
 
37948
        DUK_TVAL_INCREF(thr, tv1);
 
37949
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
37950
 
 
37951
 skip_write:
 
37952
        duk_pop(ctx);  /* remove in_val */
 
37953
}
 
37954
 
 
37955
/*
 
37956
 *  Fast path for defining array indexed values without interning the key.
 
37957
 *  This is used by e.g. code for Array prototype and traceback creation so
 
37958
 *  must avoid interning.
 
37959
 */
 
37960
 
 
37961
void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uint32_t arr_idx, duk_small_int_t flags) {
 
37962
        duk_context *ctx = (duk_context *) thr;
 
37963
        duk_hstring *key;
 
37964
        duk_tval *tv1, *tv2;
 
37965
        duk_tval tv_tmp;
 
37966
 
 
37967
        DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, arr_idx=%d, flags=0x%02x, val=%!T",
 
37968
                     (void *) thr, obj, (int) arr_idx, flags, duk_get_tval(ctx, -1));
 
37969
 
 
37970
        DUK_ASSERT(thr != NULL);
 
37971
        DUK_ASSERT(thr->heap != NULL);
 
37972
        DUK_ASSERT(obj != NULL);
 
37973
 
 
37974
        if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
 
37975
            arr_idx != DUK__NO_ARRAY_INDEX &&
 
37976
            flags == DUK_PROPDESC_FLAGS_WEC) {
 
37977
                DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0);  /* covered by comparison */
 
37978
 
 
37979
                DUK_DDDPRINT("define property to array part (property may or may not exist yet)");
 
37980
 
 
37981
                /* always grow the array, no sparse / abandon support here */
 
37982
                if (arr_idx >= obj->a_size) {
 
37983
                        duk__grow_props_for_array_item(thr, obj, arr_idx);
 
37984
                }
 
37985
 
 
37986
                DUK_ASSERT(arr_idx < obj->a_size);
 
37987
                tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(obj, arr_idx);
 
37988
                tv2 = duk_require_tval(ctx, -1);
 
37989
 
 
37990
                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
37991
                DUK_TVAL_SET_TVAL(tv1, tv2);
 
37992
                DUK_TVAL_INCREF(thr, tv1);
 
37993
                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
37994
 
 
37995
                duk_pop(ctx);  /* [ ...val ] -> [ ... ] */
 
37996
                return;
 
37997
        }
 
37998
 
 
37999
        DUK_DDDPRINT("define property fast path didn't work, use slow path");
 
38000
 
 
38001
        duk_push_number(ctx, (double) arr_idx);
 
38002
        key = duk_to_hstring(ctx, -1);
 
38003
        DUK_ASSERT(key != NULL);
 
38004
        duk_insert(ctx, -2);  /* [ ... val key ] -> [ ... key val ] */
 
38005
 
 
38006
        duk_hobject_define_property_internal(thr, obj, key, flags);
 
38007
 
 
38008
        duk_pop(ctx);  /* [ ... key ] -> [ ... ] */
 
38009
}
 
38010
 
 
38011
/*
 
38012
 *  Internal helper for defining an accessor property, ignoring
 
38013
 *  normal semantics such as extensibility, write protection etc.
 
38014
 *  Overwrites any existing value and attributes.  This is called
 
38015
 *  very rarely, so the implementation first sets a value to undefined
 
38016
 *  and then changes the entry to an accessor (this is to save code space).
 
38017
 */
 
38018
 
 
38019
void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_int_t propflags) {
 
38020
        duk_context *ctx = (duk_context *) thr;
 
38021
        int e_idx;
 
38022
        int h_idx;
 
38023
 
 
38024
        DUK_DDDPRINT("define new accessor (internal): thr=%p, obj=%!O, key=%!O, getter=%!O, setter=%!O, flags=0x%02x",
 
38025
                     (void *) thr, obj, key, getter, setter, propflags);
 
38026
 
 
38027
        DUK_ASSERT(thr != NULL);
 
38028
        DUK_ASSERT(thr->heap != NULL);
 
38029
        DUK_ASSERT(obj != NULL);
 
38030
        DUK_ASSERT(key != NULL);
 
38031
        DUK_ASSERT((propflags & ~DUK_PROPDESC_FLAGS_MASK) == 0);
 
38032
        /* setter and/or getter may be NULL */
 
38033
 
 
38034
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
38035
 
 
38036
        /* force the property to 'undefined' to create a slot for it */
 
38037
        duk_push_undefined(ctx);
 
38038
        duk_hobject_define_property_internal(thr, obj, key, propflags);
 
38039
        duk_hobject_find_existing_entry(obj, key, &e_idx, &h_idx);
 
38040
        DUK_DDDPRINT("accessor slot: e_idx=%d, h_idx=%d", e_idx, h_idx);
 
38041
        DUK_ASSERT(e_idx >= 0);
 
38042
        DUK_ASSERT(e_idx < (int) obj->e_used);  /* FIXME: e_idx typing */
 
38043
 
 
38044
        /* no need to decref, as previous value is 'undefined' */
 
38045
        DUK_HOBJECT_E_SLOT_SET_ACCESSOR(obj, e_idx);
 
38046
        DUK_HOBJECT_E_SET_VALUE_GETTER(obj, e_idx, getter);
 
38047
        DUK_HOBJECT_E_SET_VALUE_SETTER(obj, e_idx, setter);
 
38048
        DUK_HOBJECT_INCREF(thr, getter);
 
38049
        DUK_HOBJECT_INCREF(thr, setter);
 
38050
}
 
38051
 
 
38052
/*
 
38053
 *  Internal helpers for managing object 'length'
 
38054
 */
 
38055
 
 
38056
/* FIXME: awkward helpers */
 
38057
 
 
38058
void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
 
38059
        duk_context *ctx = (duk_context *) thr;
 
38060
        duk_push_hobject(ctx, obj);
 
38061
        duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
 
38062
        duk_push_number(ctx, (double) length);  /* FIXME: push_u32 */
 
38063
        (void) duk_hobject_putprop(thr, duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0);
 
38064
        duk_pop_n(ctx, 3);
 
38065
}
 
38066
 
 
38067
void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
 
38068
        duk_hobject_set_length(thr, obj, 0);
 
38069
}
 
38070
 
 
38071
duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
 
38072
        duk_context *ctx = (duk_context *) thr;
 
38073
        double val;
 
38074
        duk_push_hobject(ctx, obj);
 
38075
        duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
 
38076
        (void) duk_hobject_getprop(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
38077
        val = duk_to_number(ctx, -1);
 
38078
        duk_pop_n(ctx, 3);
 
38079
        if (val >= 0.0 && val < 4294967296.0) {  /* XXX: constant */
 
38080
                return (duk_uint32_t) val;
 
38081
        }
 
38082
        return 0;
 
38083
}
 
38084
 
 
38085
/*
 
38086
 *  Object.getOwnPropertyDescriptor()  (E5 Sections 15.2.3.3, 8.10.4)
 
38087
 *
 
38088
 *  This is an actual function call.
 
38089
 */
 
38090
 
 
38091
int duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
 
38092
        duk_hthread *thr = (duk_hthread *) ctx;
 
38093
        duk_hobject *obj;
 
38094
        duk_hstring *key;
 
38095
        duk_propdesc pd;
 
38096
        int rc;
 
38097
 
 
38098
        DUK_ASSERT(ctx != NULL);
 
38099
        DUK_ASSERT(thr != NULL);
 
38100
        DUK_ASSERT(thr->heap != NULL);
 
38101
 
 
38102
        obj = duk_require_hobject(ctx, 0);
 
38103
        (void) duk_to_string(ctx, 1);
 
38104
        key = duk_require_hstring(ctx, 1);
 
38105
 
 
38106
        DUK_ASSERT(obj != NULL);
 
38107
        DUK_ASSERT(key != NULL);
 
38108
 
 
38109
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
38110
 
 
38111
        rc = duk__get_own_property_desc(thr, obj, key, &pd, 1);  /* push_value = 1 */
 
38112
        if (!rc) {
 
38113
                duk_push_undefined(ctx);
 
38114
 
 
38115
                /* [obj key undefined] */
 
38116
                return 1;
 
38117
        }
 
38118
 
 
38119
        duk_push_object(ctx);
 
38120
 
 
38121
        /* [obj key value desc] */
 
38122
 
 
38123
        if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
 
38124
                /* If a setter/getter is missing (undefined), the descriptor must
 
38125
                 * still have the property present with the value 'undefined'.
 
38126
                 */
 
38127
                if (pd.get) {
 
38128
                        duk_push_hobject(ctx, pd.get);
 
38129
                } else {
 
38130
                        duk_push_undefined(ctx);
 
38131
                }
 
38132
                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_GET);
 
38133
                if (pd.set) {
 
38134
                        duk_push_hobject(ctx, pd.set);
 
38135
                } else {
 
38136
                        duk_push_undefined(ctx);
 
38137
                }
 
38138
                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
 
38139
        } else {
 
38140
                duk_dup(ctx, -2);  /* [obj key value desc value] */
 
38141
                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
 
38142
                duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
 
38143
                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
 
38144
 
 
38145
                /* [obj key value desc] */
 
38146
        }
 
38147
        duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
 
38148
        duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
 
38149
        duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
 
38150
        duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
 
38151
 
 
38152
        /* [obj key value desc] */
 
38153
        return 1;
 
38154
}
 
38155
 
 
38156
/*
 
38157
 *  NormalizePropertyDescriptor().
 
38158
 *
 
38159
 *  Internal helper to convert an external property descriptor on stack top
 
38160
 *  to a normalized form with plain, coerced values.  The original descriptor
 
38161
 *  object is not altered.
 
38162
 */
 
38163
 
 
38164
/* FIXME: very basic optimization -> duk_get_prop_stridx_top */
 
38165
 
 
38166
static void duk__normalize_property_descriptor(duk_context *ctx) {
 
38167
        duk_hthread *thr = (duk_hthread *) ctx;
 
38168
        int idx_in;
 
38169
        int idx_out;
 
38170
        int is_data_desc = 0;
 
38171
        int is_acc_desc = 0;
 
38172
        int target_top;
 
38173
 
 
38174
        DUK_ASSERT(ctx != NULL);
 
38175
 
 
38176
        /* must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1) */
 
38177
        (void) duk_require_hobject(ctx, -1);
 
38178
 
 
38179
        idx_in = duk_require_normalize_index(ctx, -1);
 
38180
        duk_push_object(ctx);  /* [... desc_in desc_out] */
 
38181
        idx_out = idx_in + 1;
 
38182
 
 
38183
        /* this approach allows us to be care-free with the "stack policy"
 
38184
         * until the very end.
 
38185
         */
 
38186
        target_top = duk_get_top(ctx);
 
38187
 
 
38188
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
 
38189
                is_data_desc = 1;
 
38190
                duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_VALUE);
 
38191
        }
 
38192
 
 
38193
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
 
38194
                is_data_desc = 1;
 
38195
                duk_to_boolean(ctx, -1);
 
38196
                duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_WRITABLE);
 
38197
        }
 
38198
 
 
38199
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
 
38200
                duk_tval *tv = duk_require_tval(ctx, -1);
 
38201
                is_acc_desc = 1;
 
38202
                if (DUK_TVAL_IS_UNDEFINED(tv) ||
 
38203
                    (DUK_TVAL_IS_OBJECT(tv) &&
 
38204
                     DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv)))) {
 
38205
                        duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_GET);
 
38206
                } else {
 
38207
                        goto type_error;
 
38208
                }
 
38209
        }
 
38210
 
 
38211
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
 
38212
                duk_tval *tv = duk_require_tval(ctx, -1);
 
38213
                is_acc_desc = 1;
 
38214
                if (DUK_TVAL_IS_UNDEFINED(tv) ||
 
38215
                    (DUK_TVAL_IS_OBJECT(tv) &&
 
38216
                     DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv)))) {
 
38217
                        duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_SET);
 
38218
                } else {
 
38219
                        goto type_error;
 
38220
                }
 
38221
        }
 
38222
 
 
38223
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
 
38224
                duk_to_boolean(ctx, -1);
 
38225
                duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_ENUMERABLE);
 
38226
        }
 
38227
 
 
38228
        if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
 
38229
                duk_to_boolean(ctx, -1);
 
38230
                duk_put_prop_stridx(ctx, idx_out, DUK_STRIDX_CONFIGURABLE);
 
38231
        }
 
38232
 
 
38233
        /* pop any crud */
 
38234
        duk_set_top(ctx, target_top);
 
38235
 
 
38236
        if (is_data_desc && is_acc_desc) {
 
38237
                goto type_error;
 
38238
        }
 
38239
 
 
38240
        /* [... desc_in desc_out] */
 
38241
 
 
38242
        duk_remove(ctx, -2);
 
38243
 
 
38244
        /* [... desc_out] */
 
38245
 
 
38246
        return;
 
38247
 
 
38248
 type_error:
 
38249
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid descriptor");
 
38250
}
 
38251
 
 
38252
/*
 
38253
 *  Object.defineProperty()  (E5 Section 15.2.3.6)
 
38254
 *
 
38255
 *  Inlines ToPropertyDescriptor() and all [[DefineOwnProperty]] special
 
38256
 *  behaviors.
 
38257
 *
 
38258
 *  Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
 
38259
 *  implemented directly, but Object.defineProperty() serves its purpose.
 
38260
 *  We don't need the [[DefineOwnProperty]] internally and we don't have a
 
38261
 *  property descriptor with 'missing values' so it's easier to avoid it
 
38262
 *  entirely.
 
38263
 *
 
38264
 *  This is an actual function call.
 
38265
 */
 
38266
 
 
38267
/* FIXME: this is a major target for size optimization */
 
38268
 
 
38269
int duk_hobject_object_define_property(duk_context *ctx) {
 
38270
        duk_hthread *thr = (duk_hthread *) ctx;
 
38271
        duk_hobject *obj;
 
38272
        duk_hstring *key;
 
38273
        duk_hobject *desc;
 
38274
        duk_uint32_t arr_idx;
 
38275
        int idx_desc;
 
38276
        duk_tval tv;
 
38277
        int has_enumerable;
 
38278
        int has_configurable;
 
38279
        int has_writable;
 
38280
        int has_value;
 
38281
        int has_get;
 
38282
        int has_set;
 
38283
        int is_enumerable;
 
38284
        int is_configurable;
 
38285
        int is_writable;
 
38286
        int idx_value;
 
38287
        duk_hobject *get;
 
38288
        duk_hobject *set;
 
38289
        int new_flags;
 
38290
        duk_propdesc curr;
 
38291
        duk_uint32_t arridx_new_array_length;  /* != 0 => post-update for array 'length' (used when key is an array index) */
 
38292
        duk_uint32_t arrlen_old_len;
 
38293
        duk_uint32_t arrlen_new_len;
 
38294
        int pending_write_protect;
 
38295
        int throw_flag = 1;   /* Object.defineProperty() calls [[DefineOwnProperty]] with Throw=true */
 
38296
 
 
38297
        DUK_DDDPRINT("Object.defineProperty(): thr=%p obj=%!T key=%!T desc=%!T",
 
38298
                     (void *) thr, duk_get_tval(ctx, 0), duk_get_tval(ctx, 1), duk_get_tval(ctx, 2));
 
38299
 
 
38300
        DUK_ASSERT(thr != NULL);
 
38301
        DUK_ASSERT(thr->heap != NULL);
 
38302
        DUK_ASSERT(ctx != NULL);
 
38303
 
 
38304
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
38305
 
 
38306
        obj = duk_require_hobject(ctx, 0);
 
38307
        (void) duk_to_string(ctx, 1);
 
38308
        key = duk_require_hstring(ctx, 1);
 
38309
        desc = duk_require_hobject(ctx, 2);
 
38310
        DUK_UNREF(desc);
 
38311
        idx_desc = 2;
 
38312
 
 
38313
        DUK_ASSERT(obj != NULL);
 
38314
        DUK_ASSERT(key != NULL);
 
38315
        DUK_ASSERT(desc != NULL);
 
38316
 
 
38317
        arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
 
38318
 
 
38319
        DUK_DDDPRINT("Object.defineProperty(): thr=%p obj=%!O key=%!O arr_idx=0x%08x desc=%!O",
 
38320
                     (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key, (int) arr_idx, (duk_heaphdr *) desc);
 
38321
 
 
38322
        /* Many of the above are just assigned over but are given base values to
 
38323
         * avoid warnings with some compilers.  But because the values are unused,
 
38324
         * scan-build will complain about them; silence with DUK_UNREF().
 
38325
         */
 
38326
 
 
38327
        has_enumerable = 0; DUK_UNREF(has_enumerable);
 
38328
        has_configurable = 0; DUK_UNREF(has_configurable);
 
38329
        has_value = 0; DUK_UNREF(has_value);
 
38330
        has_writable = 0; DUK_UNREF(has_writable);
 
38331
        has_get = 0; DUK_UNREF(has_get);
 
38332
        has_set = 0; DUK_UNREF(has_set);
 
38333
        is_enumerable = 0; DUK_UNREF(is_enumerable);
 
38334
        is_configurable = 0; DUK_UNREF(is_configurable);
 
38335
        is_writable = 0; DUK_UNREF(is_writable);
 
38336
        idx_value = -1; DUK_UNREF(idx_value);
 
38337
        get = NULL; DUK_UNREF(get);
 
38338
        set = NULL; DUK_UNREF(set);
 
38339
 
 
38340
        arridx_new_array_length = 0;
 
38341
        pending_write_protect = 0;
 
38342
        arrlen_old_len = 0;
 
38343
        arrlen_new_len = 0;
 
38344
 
 
38345
        /*
 
38346
         *  Extract property descriptor values as required in ToPropertyDescriptor().
 
38347
         *  However, don't create an explicit property descriptor object: we don't
 
38348
         *  want to create a new Ecmascript object, and the internal property descriptor
 
38349
         *  does not support partial descriptors.
 
38350
         *
 
38351
         *  Note that ToPropertyDescriptor() does coercions with potential errors, so
 
38352
         *  all coercions must be done first.  Boolean conversion of 'undefined' is false.
 
38353
         */
 
38354
 
 
38355
        is_enumerable = duk_get_prop_stridx_boolean(ctx, idx_desc, DUK_STRIDX_ENUMERABLE, &has_enumerable);
 
38356
        is_configurable = duk_get_prop_stridx_boolean(ctx, idx_desc, DUK_STRIDX_CONFIGURABLE, &has_configurable);
 
38357
 
 
38358
        has_value = duk_get_prop_stridx(ctx, idx_desc, DUK_STRIDX_VALUE);
 
38359
        if (has_value) {
 
38360
                /* Note: we don't want to store a pointer to an duk_tval in the
 
38361
                 * valstack here, because a valstack resize (which may occur
 
38362
                 * on any gc) might invalidate it.
 
38363
                 */
 
38364
                idx_value = duk_require_top_index(ctx);
 
38365
        } else {
 
38366
                idx_value = -1;
 
38367
        }
 
38368
        /* leave value on stack intentionally to ensure we can refer to it later */
 
38369
 
 
38370
        is_writable = duk_get_prop_stridx_boolean(ctx, idx_desc, DUK_STRIDX_WRITABLE, &has_writable);
 
38371
 
 
38372
        has_get = duk_get_prop_stridx(ctx, idx_desc, DUK_STRIDX_GET);
 
38373
        get = NULL;
 
38374
        if (has_get && !duk_is_undefined(ctx, -1)) {
 
38375
                /* FIXME: get = duk_require_callable_hobject(ctx, -1)? */
 
38376
                get = duk_require_hobject(ctx, -1);
 
38377
                DUK_ASSERT(get != NULL);
 
38378
                if (!DUK_HOBJECT_IS_CALLABLE(get)) {
 
38379
                        goto fail_invalid_desc;
 
38380
                }
 
38381
        }
 
38382
        /* leave get on stack */
 
38383
 
 
38384
        has_set = duk_get_prop_stridx(ctx, idx_desc, DUK_STRIDX_SET);
 
38385
        set = NULL;
 
38386
        if (has_set && !duk_is_undefined(ctx, -1)) {
 
38387
                set = duk_require_hobject(ctx, -1);
 
38388
                DUK_ASSERT(set != NULL);
 
38389
                if (!DUK_HOBJECT_IS_CALLABLE(set)) {
 
38390
                        goto fail_invalid_desc;
 
38391
                }
 
38392
        }
 
38393
        /* leave set on stack */
 
38394
 
 
38395
        if ((has_set || has_get) && (has_value || has_writable)) {
 
38396
                goto fail_invalid_desc;
 
38397
        }
 
38398
 
 
38399
        /* [obj key desc value get set] */
 
38400
 
 
38401
        DUK_DDDPRINT("has_enumerable=%d is_enumerable=%d "
 
38402
                     "has_configurable=%d is_configurable=%d "
 
38403
                     "has_writable=%d is_writable=%d "
 
38404
                     "has_value=%d value=%!T "
 
38405
                     "has_get=%d get=%p=%!O "
 
38406
                     "has_set=%d set=%p=%!O ",
 
38407
                     has_enumerable, is_enumerable,
 
38408
                     has_configurable, is_configurable,
 
38409
                     has_writable, is_writable,
 
38410
                     has_value, duk_get_tval(ctx, idx_value),
 
38411
                     has_get, (void *) get, (duk_heaphdr *) get,
 
38412
                     has_set, (void *) set, (duk_heaphdr *) set);
 
38413
 
 
38414
        /*
 
38415
         *  Array special behaviors can be implemented at this point.  The local variables
 
38416
         *  are essentially a 'value copy' of the input descriptor (Desc), which is modified
 
38417
         *  by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
 
38418
         */
 
38419
 
 
38420
        if (!DUK_HOBJECT_HAS_SPECIAL_ARRAY(obj)) {
 
38421
                goto skip_array_special;
 
38422
        }
 
38423
 
 
38424
        if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
 
38425
                /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
 
38426
                if (!has_value) {
 
38427
                        DUK_DDDPRINT("special array behavior for 'length', but no value in descriptor -> normal behavior");
 
38428
                        goto skip_array_special;
 
38429
                }
 
38430
        
 
38431
                DUK_DDDPRINT("special array behavior for 'length', value present in descriptor -> special behavior");
 
38432
 
 
38433
                /*
 
38434
                 *  Get old and new length
 
38435
                 */
 
38436
 
 
38437
                /* Note: reuse 'curr' as a temp propdesc */
 
38438
                arrlen_old_len = duk__get_old_array_length(thr, obj, &curr);
 
38439
 
 
38440
                duk_dup(ctx, idx_value);
 
38441
                arrlen_new_len = duk__to_new_array_length_checked(thr);
 
38442
                duk_replace(ctx, idx_value);  /* step 3.e: replace 'Desc.[[Value]]' */
 
38443
 
 
38444
                DUK_DDDPRINT("old_len=%d, new_len=%d", arrlen_old_len, arrlen_new_len);
 
38445
 
 
38446
                if (arrlen_new_len >= arrlen_old_len) {
 
38447
                        /* standard behavior, step 3.f.i */
 
38448
                        DUK_DDDPRINT("new length is same or higher as previous => standard behavior");
 
38449
                        goto skip_array_special;
 
38450
                }
 
38451
                DUK_DDDPRINT("new length is smaller than previous => special post behavior");
 
38452
 
 
38453
                /* FIXME: consolidated algorithm step 15.f -> redundant? */
 
38454
                if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
38455
                        /* Note: 'curr' refers to 'length' propdesc */
 
38456
                        goto fail_not_writable_array_length;
 
38457
                }
 
38458
 
 
38459
                /* steps 3.h and 3.i */
 
38460
                if (has_writable && !is_writable) {
 
38461
                        DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect");
 
38462
                        is_writable = 1;
 
38463
                        pending_write_protect = 1;
 
38464
                }
 
38465
 
 
38466
                /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
 
38467
        } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
 
38468
                /* FIXME: any chance of unifying this with the 'length' key handling? */
 
38469
 
 
38470
                /* E5 Section 15.4.5.1, step 4 */
 
38471
                duk_uint32_t old_len;
 
38472
 
 
38473
                /* Note: use 'curr' as a temp propdesc */
 
38474
                old_len = duk__get_old_array_length(thr, obj, &curr);
 
38475
 
 
38476
                if (arr_idx >= old_len) {
 
38477
                        DUK_DDDPRINT("defineProperty requires array length update "
 
38478
                                     "(arr_idx=%d, old_len=%d)",
 
38479
                                     arr_idx, old_len);
 
38480
 
 
38481
                        if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
38482
                                /* Note: 'curr' refers to 'length' propdesc */
 
38483
                                goto fail_not_writable_array_length;
 
38484
                        }
 
38485
 
 
38486
                        /* actual update happens once write has been completed without
 
38487
                         * error below.
 
38488
                         */
 
38489
                        DUK_ASSERT(arr_idx != 0xffffffffU);
 
38490
                        arridx_new_array_length = arr_idx + 1;
 
38491
                } else {
 
38492
                        DUK_DDDPRINT("defineProperty does not require length update "
 
38493
                                     "(arr_idx=%d, old_len=%d) -> standard behavior",
 
38494
                                     arr_idx, old_len);
 
38495
                }
 
38496
        }
 
38497
 skip_array_special:
 
38498
 
 
38499
        /*
 
38500
         *  Actual Object.defineProperty() default algorithm.
 
38501
         */
 
38502
 
 
38503
        /*
 
38504
         *  First check whether property exists; if not, simple case.  This covers
 
38505
         *  steps 1-4.
 
38506
         */
 
38507
 
 
38508
        if (!duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &curr, 1)) {
 
38509
                DUK_DDDPRINT("property does not exist");
 
38510
 
 
38511
                if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
 
38512
                        goto fail_not_extensible;
 
38513
                }
 
38514
 
 
38515
                /* FIXME: share final setting code for value and flags?  difficult because
 
38516
                 * refcount code is different.  Share entry allocation?  But can't allocate
 
38517
                 * until array index checked.
 
38518
                 */
 
38519
 
 
38520
                /* steps 4.a and 4.b are tricky */
 
38521
                if (has_set || has_get) {
 
38522
                        int e_idx;
 
38523
 
 
38524
                        DUK_DDDPRINT("create new accessor property");
 
38525
 
 
38526
                        DUK_ASSERT(has_set || set == NULL);
 
38527
                        DUK_ASSERT(has_get || get == NULL);
 
38528
                        DUK_ASSERT(!has_value);
 
38529
                        DUK_ASSERT(!has_writable);
 
38530
 
 
38531
                        new_flags = DUK_PROPDESC_FLAG_ACCESSOR;  /* defaults, E5 Section 8.6.1, Table 7 */
 
38532
                        if (has_enumerable && is_enumerable) {
 
38533
                                new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
 
38534
                        }
 
38535
                        if (has_configurable && is_configurable) {
 
38536
                                new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
 
38537
                        }
 
38538
 
 
38539
                        if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
 
38540
                                DUK_DDDPRINT("accessor cannot go to array part, abandon array");
 
38541
                                duk__abandon_array_checked(thr, obj);
 
38542
                        }
 
38543
 
 
38544
                        /* write to entry part */
 
38545
                        e_idx = duk__alloc_entry_checked(thr, obj, key);
 
38546
                        DUK_ASSERT(e_idx >= 0);
 
38547
 
 
38548
                        DUK_HOBJECT_E_SET_VALUE_GETTER(obj, e_idx, get);
 
38549
                        DUK_HOBJECT_E_SET_VALUE_SETTER(obj, e_idx, set);
 
38550
                        DUK_HOBJECT_INCREF(thr, get);
 
38551
                        DUK_HOBJECT_INCREF(thr, set);
 
38552
 
 
38553
                        DUK_HOBJECT_E_SET_FLAGS(obj, e_idx, new_flags);
 
38554
                        goto success_specials;
 
38555
                } else {
 
38556
                        int e_idx;
 
38557
                        duk_tval *tv2;
 
38558
 
 
38559
                        DUK_DDDPRINT("create new data property");
 
38560
 
 
38561
                        DUK_ASSERT(!has_set);
 
38562
                        DUK_ASSERT(!has_get);
 
38563
 
 
38564
                        new_flags = 0;  /* defaults, E5 Section 8.6.1, Table 7 */
 
38565
                        if (has_writable && is_writable) {
 
38566
                                new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
 
38567
                        }
 
38568
                        if (has_enumerable && is_enumerable) {
 
38569
                                new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
 
38570
                        }
 
38571
                        if (has_configurable && is_configurable) {
 
38572
                                new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
 
38573
                        }
 
38574
                        if (has_value) {
 
38575
                                duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
 
38576
                                DUK_TVAL_SET_TVAL(&tv, tv_tmp);
 
38577
                        } else {
 
38578
                                DUK_TVAL_SET_UNDEFINED_ACTUAL(&tv);  /* default value */
 
38579
                        }
 
38580
 
 
38581
                        if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
 
38582
                                if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
 
38583
#if 0
 
38584
                                        DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part");
 
38585
                                        /* may become sparse...*/
 
38586
#endif
 
38587
                                        /* FIXME: handling for array part missing now; this doesn't affect
 
38588
                                         * compliance but causes array entry writes using defineProperty()
 
38589
                                         * to always abandon array part.
 
38590
                                         */
 
38591
                                }
 
38592
                                DUK_DDDPRINT("new data property cannot go to array part, abandon array");
 
38593
                                duk__abandon_array_checked(thr, obj);
 
38594
                                /* fall through */
 
38595
                        }
 
38596
 
 
38597
                        /* write to entry part */
 
38598
                        e_idx = duk__alloc_entry_checked(thr, obj, key);
 
38599
                        DUK_ASSERT(e_idx >= 0);
 
38600
                        tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, e_idx);
 
38601
                        DUK_TVAL_SET_TVAL(tv2, &tv);
 
38602
                        DUK_TVAL_INCREF(thr, tv2);
 
38603
 
 
38604
                        DUK_HOBJECT_E_SET_FLAGS(obj, e_idx, new_flags);
 
38605
                        goto success_specials;
 
38606
                }
 
38607
                DUK_UNREACHABLE();
 
38608
        }
 
38609
 
 
38610
        /* we currently assume virtual properties are not configurable (as none of them are) */
 
38611
        DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
 
38612
 
 
38613
        /* [obj key desc value get set curr_value] */
 
38614
 
 
38615
        /*
 
38616
         *  Property already exists.  Steps 5-6 detect whether any changes need
 
38617
         *  to be made.
 
38618
         */
 
38619
 
 
38620
        if (has_enumerable) {
 
38621
                if (is_enumerable) {
 
38622
                        if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
 
38623
                                goto need_check;
 
38624
                        }
 
38625
                } else {
 
38626
                        if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
 
38627
                                goto need_check;
 
38628
                        }
 
38629
                }
 
38630
        }
 
38631
        if (has_configurable) {
 
38632
                if (is_configurable) {
 
38633
                        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38634
                                goto need_check;
 
38635
                        }
 
38636
                } else {
 
38637
                        if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
 
38638
                                goto need_check;
 
38639
                        }
 
38640
                }
 
38641
        }
 
38642
        if (has_value) {
 
38643
                duk_tval *tmp1;
 
38644
                duk_tval *tmp2;
 
38645
        
 
38646
                /* attempt to change from accessor to data property */
 
38647
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38648
                        goto need_check;
 
38649
                }
 
38650
 
 
38651
                tmp1 = duk_require_tval(ctx, -1);         /* curr value */
 
38652
                tmp2 = duk_require_tval(ctx, idx_value);  /* new value */
 
38653
                if (!duk_js_samevalue(tmp1, tmp2)) {
 
38654
                        goto need_check;
 
38655
                }
 
38656
        }
 
38657
        if (has_writable) {
 
38658
                /* attempt to change from accessor to data property */
 
38659
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38660
                        goto need_check;
 
38661
                }
 
38662
 
 
38663
                if (is_writable) {
 
38664
                        if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
38665
                                goto need_check;
 
38666
                        }
 
38667
                } else {
 
38668
                        if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
 
38669
                                goto need_check;
 
38670
                        }
 
38671
                }
 
38672
        }
 
38673
        if (has_set) {
 
38674
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38675
                        if (set != curr.set) {
 
38676
                                goto need_check;
 
38677
                        }
 
38678
                } else {
 
38679
                        goto need_check;
 
38680
                }
 
38681
        }
 
38682
        if (has_get) {
 
38683
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38684
                        if (get != curr.get) {
 
38685
                                goto need_check;
 
38686
                        }
 
38687
                } else {
 
38688
                        goto need_check;
 
38689
                }
 
38690
        }
 
38691
 
 
38692
        /* property exists, either 'desc' is empty, or all values
 
38693
         * match (SameValue)
 
38694
         */
 
38695
        goto success_no_specials;
 
38696
 
 
38697
 need_check:
 
38698
 
 
38699
        /*
 
38700
         *  Some change(s) need to be made.  Steps 7-11.
 
38701
         */
 
38702
 
 
38703
        /* shared checks for all descriptor types */
 
38704
        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38705
                if (has_configurable && is_configurable) {
 
38706
                        goto fail_not_configurable;
 
38707
                }
 
38708
                if (has_enumerable) {
 
38709
                        if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
 
38710
                                if (!is_enumerable) {
 
38711
                                        goto fail_not_configurable;
 
38712
                                }
 
38713
                        } else {
 
38714
                                if (is_enumerable) {
 
38715
                                        goto fail_not_configurable;
 
38716
                                }
 
38717
                        }
 
38718
                }
 
38719
        }
 
38720
 
 
38721
        /* reject attempt to change virtual properties: not part of the
 
38722
         * standard algorithm, applies currently to e.g. virtual index
 
38723
         * properties of buffer objects (which are virtual but writable).
 
38724
         */
 
38725
        if (curr.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
 
38726
                goto fail_virtual;
 
38727
        }
 
38728
 
 
38729
        /* descriptor type specific checks */
 
38730
        if (has_set || has_get) {
 
38731
                /* IsAccessorDescriptor(desc) == true */
 
38732
                DUK_ASSERT(!has_writable);
 
38733
                DUK_ASSERT(!has_value);
 
38734
 
 
38735
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38736
                        /* curr and desc are accessors */
 
38737
                        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38738
                                if (has_set && set != curr.set) {
 
38739
                                        goto fail_not_configurable;
 
38740
                                }
 
38741
                                if (has_get && get != curr.get) {
 
38742
                                        goto fail_not_configurable;
 
38743
                                }
 
38744
                        }
 
38745
                } else {
 
38746
                        int rc;
 
38747
                        duk_tval tv_tmp;
 
38748
                        duk_tval *tv1;
 
38749
 
 
38750
                        /* curr is data, desc is accessor */
 
38751
                        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38752
                                goto fail_not_configurable;
 
38753
                        }
 
38754
 
 
38755
                        DUK_DDDPRINT("convert property to accessor property");
 
38756
                        if (curr.a_idx >= 0) {
 
38757
                                int rc;
 
38758
 
 
38759
                                DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup");
 
38760
                                duk__abandon_array_checked(thr, obj);
 
38761
                                duk_pop(ctx);  /* remove old value */
 
38762
                                rc = duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &curr, 1);
 
38763
                                DUK_UNREF(rc);
 
38764
                                DUK_ASSERT(rc != 0);
 
38765
                                DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
 
38766
                        }
 
38767
 
 
38768
                        DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
38769
 
 
38770
                        tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, curr.e_idx);
 
38771
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
38772
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv1);
 
38773
                        DUK_TVAL_DECREF(thr, &tv_tmp);
 
38774
 
 
38775
                        DUK_HOBJECT_E_SET_VALUE_GETTER(obj, curr.e_idx, NULL);
 
38776
                        DUK_HOBJECT_E_SET_VALUE_SETTER(obj, curr.e_idx, NULL);
 
38777
                        DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(obj, curr.e_idx);
 
38778
                        DUK_HOBJECT_E_SLOT_SET_ACCESSOR(obj, curr.e_idx);
 
38779
 
 
38780
                        DUK_DDDPRINT("flags after data->accessor conversion: 0x%02x", (int) DUK_HOBJECT_E_GET_FLAGS(obj, curr.e_idx));
 
38781
 
 
38782
                        /* re-lookup to update curr.flags -- FIXME: faster to update directly */
 
38783
                        duk_pop(ctx);  /* remove old value */
 
38784
                        rc = duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &curr, 1);
 
38785
                        DUK_UNREF(rc);
 
38786
                        DUK_ASSERT(rc != 0);
 
38787
                }
 
38788
        } else if (has_value || has_writable) {
 
38789
                /* IsDataDescriptor(desc) == true */
 
38790
                DUK_ASSERT(!has_set);
 
38791
                DUK_ASSERT(!has_get);
 
38792
 
 
38793
                if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
38794
                        int rc;
 
38795
                        duk_hobject *tmp;
 
38796
 
 
38797
                        /* curr is accessor, desc is data */
 
38798
                        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38799
                                goto fail_not_configurable;
 
38800
                        }
 
38801
 
 
38802
                        /* curr is accessor -> cannot be in array part */
 
38803
                        DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
 
38804
 
 
38805
                        DUK_DDDPRINT("convert property to data property");
 
38806
 
 
38807
                        DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
38808
                        tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(obj, curr.e_idx);
 
38809
                        DUK_UNREF(tmp);
 
38810
                        DUK_HOBJECT_E_SET_VALUE_GETTER(obj, curr.e_idx, NULL);
 
38811
                        DUK_HOBJECT_DECREF(thr, tmp);
 
38812
                        tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(obj, curr.e_idx);
 
38813
                        DUK_UNREF(tmp);
 
38814
                        DUK_HOBJECT_E_SET_VALUE_SETTER(obj, curr.e_idx, NULL);
 
38815
                        DUK_HOBJECT_DECREF(thr, tmp);
 
38816
 
 
38817
                        DUK_TVAL_SET_UNDEFINED_ACTUAL(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, curr.e_idx));
 
38818
                        DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(obj, curr.e_idx);
 
38819
                        DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(obj, curr.e_idx);
 
38820
 
 
38821
                        DUK_DDDPRINT("flags after accessor->data conversion: 0x%02x", (int) DUK_HOBJECT_E_GET_FLAGS(obj, curr.e_idx));
 
38822
 
 
38823
                        /* re-lookup to update curr.flags -- FIXME: faster to update directly */
 
38824
                        duk_pop(ctx);  /* remove old value */
 
38825
                        rc = duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &curr, 1);
 
38826
                        DUK_UNREF(rc);
 
38827
                        DUK_ASSERT(rc != 0);
 
38828
                } else {
 
38829
                        /* curr and desc are data */
 
38830
                        if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
38831
                                if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
 
38832
                                        goto fail_not_configurable;
 
38833
                                }
 
38834
                                /* Note: changing from writable to non-writable is OK */
 
38835
                                if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
 
38836
                                        duk_tval *tmp1 = duk_require_tval(ctx, -1);         /* curr value */
 
38837
                                        duk_tval *tmp2 = duk_require_tval(ctx, idx_value);  /* new value */
 
38838
                                        if (!duk_js_samevalue(tmp1, tmp2)) {
 
38839
                                                goto fail_not_configurable;
 
38840
                                        }
 
38841
                                }
 
38842
                        }
 
38843
                }
 
38844
        } else {
 
38845
                /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
 
38846
                 * only has [[Enumerable]] or [[Configurable]] flag updates, which are
 
38847
                 * allowed at this point.
 
38848
                 */
 
38849
 
 
38850
                DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
 
38851
        }
 
38852
 
 
38853
        /*
 
38854
         *  Start doing property attributes updates.  Steps 12-13.
 
38855
         *
 
38856
         *  Start by computing new attribute flags without writing yet.
 
38857
         *  Property type conversion is done above if necessary.
 
38858
         */
 
38859
 
 
38860
        new_flags = curr.flags;
 
38861
 
 
38862
        if (has_enumerable) {
 
38863
                if (is_enumerable) {
 
38864
                        new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
 
38865
                } else {
 
38866
                        new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
 
38867
                }
 
38868
        }
 
38869
        if (has_configurable) {
 
38870
                if (is_configurable) {
 
38871
                        new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
 
38872
                } else {
 
38873
                        new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
 
38874
                }
 
38875
        }
 
38876
        if (has_writable) {
 
38877
                if (is_writable) {
 
38878
                        new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
 
38879
                } else {
 
38880
                        new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
 
38881
                }
 
38882
        }
 
38883
 
 
38884
        /* FIXME: write protect after flag? -> any chance of handling it here? */
 
38885
 
 
38886
        DUK_DDDPRINT("new flags that we want to write: 0x%02x", new_flags);
 
38887
 
 
38888
        /*
 
38889
         *  Check whether we need to abandon an array part (if it exists)
 
38890
         */
 
38891
 
 
38892
        if (curr.a_idx >= 0) {
 
38893
                int rc;
 
38894
 
 
38895
                DUK_ASSERT(curr.e_idx < 0);
 
38896
 
 
38897
                if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
 
38898
                        duk_tval *tv1, *tv2;
 
38899
                        duk_tval tv_tmp;
 
38900
 
 
38901
                        DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place");
 
38902
 
 
38903
                        DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC);  /* must have been, since in array part */
 
38904
                        DUK_ASSERT(!has_set);
 
38905
                        DUK_ASSERT(!has_get);
 
38906
 
 
38907
                        tv2 = duk_require_tval(ctx, idx_value);
 
38908
                        tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(obj, curr.a_idx);
 
38909
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
38910
                        DUK_TVAL_SET_TVAL(tv1, tv2);
 
38911
                        DUK_TVAL_INCREF(thr, tv1);
 
38912
                        DUK_TVAL_DECREF(thr, &tv_tmp);
 
38913
                        goto success_specials;
 
38914
                }
 
38915
 
 
38916
                DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup");
 
38917
                duk__abandon_array_checked(thr, obj);
 
38918
                duk_pop(ctx);  /* remove old value */
 
38919
                rc = duk__get_own_property_desc_raw(thr, obj, key, arr_idx, &curr, 1);
 
38920
                DUK_UNREF(rc);
 
38921
                DUK_ASSERT(rc != 0);
 
38922
                DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
 
38923
        }
 
38924
 
 
38925
        DUK_DDDPRINT("updating existing property in entry part");
 
38926
 
 
38927
        /* array case is handled comprehensively above */
 
38928
        DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
 
38929
 
 
38930
        DUK_DDDPRINT("update existing property attributes");
 
38931
        DUK_HOBJECT_E_SET_FLAGS(obj, curr.e_idx, new_flags);
 
38932
 
 
38933
        if (has_set) {
 
38934
                duk_hobject *tmp;
 
38935
 
 
38936
                DUK_DDDPRINT("update existing property setter");
 
38937
                DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
38938
 
 
38939
                tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(obj, curr.e_idx);
 
38940
                DUK_UNREF(tmp);
 
38941
                DUK_HOBJECT_E_SET_VALUE_SETTER(obj, curr.e_idx, set);
 
38942
                DUK_HOBJECT_INCREF(thr, set);
 
38943
                DUK_HOBJECT_DECREF(thr, tmp);
 
38944
        }
 
38945
        if (has_get) {
 
38946
                duk_hobject *tmp;
 
38947
 
 
38948
                DUK_DDDPRINT("update existing property getter");
 
38949
                DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
38950
 
 
38951
                tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(obj, curr.e_idx);
 
38952
                DUK_UNREF(tmp);
 
38953
                DUK_HOBJECT_E_SET_VALUE_GETTER(obj, curr.e_idx, get);
 
38954
                DUK_HOBJECT_INCREF(thr, get);
 
38955
                DUK_HOBJECT_DECREF(thr, tmp);
 
38956
        }
 
38957
        if (has_value) {
 
38958
                duk_tval *tv1, *tv2;
 
38959
                duk_tval tv_tmp;
 
38960
 
 
38961
                DUK_DDDPRINT("update existing property value");
 
38962
                DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
38963
 
 
38964
                tv2 = duk_require_tval(ctx, idx_value);
 
38965
                tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, curr.e_idx);
 
38966
                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
38967
                DUK_TVAL_SET_TVAL(tv1, tv2);
 
38968
                DUK_TVAL_INCREF(thr, tv1);
 
38969
                DUK_TVAL_DECREF(thr, &tv_tmp);
 
38970
        }
 
38971
 
 
38972
        /*
 
38973
         *  Standard algorithm succeeded without errors, check for special post-behaviors.
 
38974
         *
 
38975
         *  Arguments special behavior in E5 Section 10.6 occurs after the standard
 
38976
         *  [[DefineOwnProperty]] has completed successfully.
 
38977
         *
 
38978
         *  Array special behavior in E5 Section 15.4.5.1 is implemented partly
 
38979
         *  prior to the default [[DefineOwnProperty]], but:
 
38980
         *    - for an array index key (e.g. "10") the final 'length' update occurs here
 
38981
         *    - for 'length' key the element deletion and 'length' update occurs here
 
38982
         */
 
38983
 
 
38984
 success_specials:
 
38985
 
 
38986
        /* [obj key desc value get set curr_value] */
 
38987
 
 
38988
        if (DUK_HOBJECT_HAS_SPECIAL_ARRAY(obj)) {
 
38989
                if (arridx_new_array_length > 0) {
 
38990
                        duk_tval *tmp;
 
38991
                        int rc;
 
38992
 
 
38993
                        /*
 
38994
                         *  Note: zero works as a "no update" marker because the new length
 
38995
                         *  can never be zero after a new property is written.
 
38996
                         */
 
38997
 
 
38998
                        /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
 
38999
 
 
39000
                        DUK_DDDPRINT("defineProperty successful, pending array length update to: %d", arridx_new_array_length);
 
39001
 
 
39002
                        /* Note: reuse 'curr' */
 
39003
                        rc = duk__get_own_property_desc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &curr, 0);
 
39004
                        DUK_UNREF(rc);
 
39005
                        DUK_ASSERT(rc != 0);
 
39006
                        DUK_ASSERT(curr.e_idx >= 0);
 
39007
 
 
39008
                        tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, curr.e_idx);
 
39009
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
 
39010
                        DUK_TVAL_SET_NUMBER(tmp, (double) arridx_new_array_length);  /* no need for decref/incref because value is a number */
 
39011
                }
 
39012
                if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
 
39013
                        /*
 
39014
                         *  E5 Section 15.4.5.1, steps 3.k - 3.n.  The order at the end combines
 
39015
                         *  the error case 3.l.iii and the success case 3.m-3.n.
 
39016
                         *
 
39017
                         *  Note: 'length' is always in entries part, so no array abandon issues for
 
39018
                         *  'writable' update.
 
39019
                         */
 
39020
 
 
39021
                        /* FIXME: investigate whether write protect can be handled above, if we
 
39022
                         * just update length here while ignoring its protected status
 
39023
                         */
 
39024
 
 
39025
                        duk_tval *tmp;
 
39026
                        duk_uint32_t result_len;
 
39027
                        int rc;
 
39028
 
 
39029
                        DUK_DDDPRINT("defineProperty successful, key is 'length', special array behavior, "
 
39030
                                     "doing array element deletion and length update");
 
39031
 
 
39032
                        rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, &result_len);
 
39033
 
 
39034
                        /* update length (curr points to length, and we assume it's still valid) */
 
39035
                        DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
 
39036
 
 
39037
                        DUK_ASSERT(curr.e_idx >= 0);
 
39038
                        DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, curr.e_idx));
 
39039
                        tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(obj, curr.e_idx);
 
39040
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
 
39041
                        DUK_TVAL_SET_NUMBER(tmp, (double) result_len);  /* no decref needed for a number */
 
39042
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
 
39043
 
 
39044
                        if (pending_write_protect) {
 
39045
                                DUK_DDDPRINT("setting array length non-writable (pending writability update)");
 
39046
                                DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(obj, curr.e_idx);
 
39047
                        }
 
39048
 
 
39049
                        /*
 
39050
                         *  FIXME: shrink array allocation or entries compaction here?
 
39051
                         */
 
39052
 
 
39053
                        if (!rc) {
 
39054
                                goto fail_array_length_partial;
 
39055
                        }
 
39056
                }
 
39057
        } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(obj)) {
 
39058
                duk_hobject *map;
 
39059
                duk_hobject *varenv;
 
39060
 
 
39061
                DUK_ASSERT(arridx_new_array_length == 0);
 
39062
                DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARRAY(obj));  /* traits are separate; in particular, arguments not an array */
 
39063
 
 
39064
                map = NULL;
 
39065
                varenv = NULL;
 
39066
                if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
 
39067
                        goto success_no_specials;
 
39068
                }
 
39069
                DUK_ASSERT(map != NULL);
 
39070
                DUK_ASSERT(varenv != NULL);
 
39071
 
 
39072
                /* [obj key desc value get set curr_value varname] */
 
39073
 
 
39074
                if (has_set || has_get) {
 
39075
                        /* = IsAccessorDescriptor(Desc) */
 
39076
                        DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
 
39077
                                     "changed to an accessor, delete arguments binding");
 
39078
 
 
39079
                        (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
 
39080
                } else {
 
39081
                        /* Note: this order matters (final value before deleting map entry must be done) */
 
39082
                        DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
 
39083
                                     "check for value update / binding deletion");
 
39084
 
 
39085
                        if (has_value) {
 
39086
                                duk_hstring *varname;
 
39087
 
 
39088
                                DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
 
39089
                                             "update bound value (variable/argument)");
 
39090
 
 
39091
                                varname = duk_require_hstring(ctx, -1);
 
39092
                                DUK_ASSERT(varname != NULL);
 
39093
 
 
39094
                                DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
 
39095
                                             "key=%!O, varname=%!O, value=%!T",
 
39096
                                             (duk_heaphdr *) key,
 
39097
                                             (duk_heaphdr *) varname,
 
39098
                                             duk_require_tval(ctx, idx_value));
 
39099
 
 
39100
                                /* strict flag for putvar comes from our caller (currently: fixed) */
 
39101
                                duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), throw_flag);
 
39102
                        }
 
39103
                        if (has_writable && !is_writable) {
 
39104
                                DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
 
39105
                                             "changed to non-writable, delete arguments binding");
 
39106
 
 
39107
                                (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
 
39108
                        }
 
39109
                }
 
39110
 
 
39111
                /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
 
39112
                 * but this doesn't matter now.
 
39113
                 */
 
39114
        }
 
39115
 
 
39116
 success_no_specials:
 
39117
        /* no need to unwind stack (rewound automatically) */
 
39118
        duk_set_top(ctx, 1);  /* -> [ obj ] */
 
39119
        return 1;
 
39120
 
 
39121
 fail_virtual:
 
39122
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "property is virtual");
 
39123
        return 0;
 
39124
 
 
39125
 fail_invalid_desc:
 
39126
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid descriptor");
 
39127
        return 0;
 
39128
 
 
39129
 fail_not_writable_array_length:
 
39130
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "array length not writable");
 
39131
        return 0;
 
39132
 
 
39133
 fail_not_extensible:
 
39134
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "object not extensible");
 
39135
        return 0;
 
39136
 
 
39137
 fail_not_configurable:
 
39138
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "property not configurable");
 
39139
        return 0;
 
39140
 
 
39141
 fail_array_length_partial:
 
39142
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "array length write failed");
 
39143
        return 0;
 
39144
}
 
39145
 
 
39146
/*
 
39147
 *  Object.defineProperties()  (E5 Section 15.2.3.7)
 
39148
 *
 
39149
 *  This is an actual function call.
 
39150
 */
 
39151
 
 
39152
int duk_hobject_object_define_properties(duk_context *ctx) {
 
39153
        duk_require_hobject(ctx, 0);  /* target */
 
39154
        duk_to_object(ctx, 1);        /* properties object */
 
39155
 
 
39156
        DUK_DDDPRINT("target=%!iT, properties=%!iT", duk_get_tval(ctx, 0), duk_get_tval(ctx, 1));
 
39157
 
 
39158
        duk_push_object(ctx);
 
39159
        duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
 
39160
 
 
39161
        /* [hobject props descriptors enum(props)] */
 
39162
 
 
39163
        DUK_DDDPRINT("enum(properties)=%!iT", duk_get_tval(ctx, 3));
 
39164
 
 
39165
        for (;;) {
 
39166
                if (!duk_next(ctx, 3, 1 /*get_value*/)) {
 
39167
                        break;
 
39168
                }
 
39169
 
 
39170
                DUK_DDDPRINT("-> key=%!iT, desc=%!iT", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
39171
 
 
39172
                /* [hobject props descriptors enum(props) key desc] */
 
39173
 
 
39174
                duk__normalize_property_descriptor(ctx);
 
39175
                
 
39176
                /* [hobject props descriptors enum(props) key desc_norm] */
 
39177
 
 
39178
                duk_put_prop(ctx, 2);
 
39179
 
 
39180
                /* [hobject props descriptors enum(props)] */
 
39181
        }
 
39182
 
 
39183
        DUK_DDDPRINT("-> descriptors=%!iT, desc=%!iT", duk_get_tval(ctx, 2));
 
39184
 
 
39185
        /* We rely on 'descriptors' having the same key order as 'props'
 
39186
         * to match the array semantics of E5 Section 15.2.3.7.
 
39187
         */
 
39188
 
 
39189
        duk_pop(ctx);
 
39190
        duk_enum(ctx, 2, 0 /*enum_flags*/);
 
39191
 
 
39192
        /* [hobject props descriptors enum(descriptors)] */
 
39193
 
 
39194
        DUK_DDDPRINT("enum(descriptors)=%!iT", duk_get_tval(ctx, 3));
 
39195
 
 
39196
        for (;;) {
 
39197
                if (!duk_next(ctx, 3, 1 /*get_value*/)) {
 
39198
                        break;
 
39199
                }
 
39200
 
 
39201
                DUK_DDDPRINT("-> key=%!iT, desc=%!iT", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
39202
 
 
39203
                /* [hobject props descriptors enum(descriptors) key desc_norm] */
 
39204
 
 
39205
                duk_dup(ctx, 0);
 
39206
                duk_insert(ctx, -3);
 
39207
 
 
39208
                /* [hobject props descriptors enum(descriptors) hobject key desc_norm] */
 
39209
 
 
39210
                /* FIXME: need access to the -original- Object.defineProperty function
 
39211
                 * object here (the property is configurable so a caller may have changed
 
39212
                 * it).  This is not a good approach.
 
39213
                 */
 
39214
                duk_push_c_function(ctx, duk_hobject_object_define_property, 3);
 
39215
                duk_insert(ctx, -4);
 
39216
 
 
39217
                /* [hobject props descriptors enum(descriptors) Object.defineProperty hobject key desc_norm] */
 
39218
 
 
39219
                duk_call(ctx, 3);
 
39220
 
 
39221
                /* [hobject props descriptors enum(descriptors) retval] */
 
39222
 
 
39223
                /* FIXME: call which ignores result would be nice */
 
39224
 
 
39225
                duk_pop(ctx);
 
39226
        }
 
39227
 
 
39228
        /* [hobject props descriptors enum(descriptors)] */
 
39229
 
 
39230
        duk_dup(ctx, 0);
 
39231
        
 
39232
        /* [hobject props descriptors enum(descriptors) hobject] */
 
39233
 
 
39234
        return 1;
 
39235
}
 
39236
 
 
39237
/*
 
39238
 *  Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
 
39239
 */
 
39240
 
 
39241
int duk_hobject_object_ownprop_helper(duk_context *ctx, int required_desc_flags) {
 
39242
        duk_hthread *thr = (duk_hthread *) ctx;
 
39243
        duk_hstring *h_v;
 
39244
        duk_hobject *h_obj;
 
39245
        duk_propdesc desc;
 
39246
        int ret;
 
39247
 
 
39248
        /* coercion order matters */
 
39249
        h_v = duk_to_hstring(ctx, 0);
 
39250
        DUK_ASSERT(h_v != NULL);
 
39251
 
 
39252
        h_obj = duk_push_this_coercible_to_object(ctx);
 
39253
        DUK_ASSERT(h_obj != NULL);
 
39254
 
 
39255
        ret = duk__get_own_property_desc(thr, h_obj, h_v, &desc, 0 /*push_value*/);
 
39256
 
 
39257
        duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
 
39258
        return 1;
 
39259
}
 
39260
 
 
39261
/*
 
39262
 *  Object.seal() and Object.freeze()  (E5 Sections 15.2.3.8 and 15.2.3.9)
 
39263
 * 
 
39264
 *  Since the algorithms are similar, a helper provides both functions.
 
39265
 *  Freezing is essentially sealing + making plain properties non-writable.
 
39266
 *
 
39267
 *  Note: virtual (non-concrete) properties which are non-configurable but
 
39268
 *  writable would pose some problems, but such properties do not currently
 
39269
 *  exist (all virtual properties are non-configurable and non-writable).
 
39270
 *  If they did exist, the non-configurability does NOT prevent them from
 
39271
 *  becoming non-writable.  However, this change should be recorded somehow
 
39272
 *  so that it would turn up (e.g. when getting the property descriptor),
 
39273
 *  requiring some additional flags in the object.
 
39274
 */
 
39275
 
 
39276
void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, int freeze) {
 
39277
        duk_uint_fast32_t i;
 
39278
 
 
39279
        DUK_ASSERT(thr != NULL);
 
39280
        DUK_ASSERT(thr->heap != NULL);
 
39281
        DUK_ASSERT(obj != NULL);
 
39282
 
 
39283
        DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
 
39284
 
 
39285
        /*
 
39286
         *  Abandon array part because all properties must become non-configurable.
 
39287
         *  Note that this is now done regardless of whether this is always the case
 
39288
         *  (skips check, but performance problem if caller would do this many times
 
39289
         *  for the same object; not likely).
 
39290
         */
 
39291
 
 
39292
        duk__abandon_array_checked(thr, obj);
 
39293
        DUK_ASSERT(obj->a_size == 0);
 
39294
 
 
39295
        for (i = 0; i < obj->e_used; i++) {
 
39296
                duk_uint8_t *fp;
 
39297
 
 
39298
                /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
 
39299
                DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(obj, i) != NULL);
 
39300
 
 
39301
                /* avoid multiple computations of flags address; bypasses macros */
 
39302
                fp = DUK_HOBJECT_E_GET_FLAGS_PTR(obj, i);
 
39303
                if (freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
 
39304
                        *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
 
39305
                } else {
 
39306
                        *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
 
39307
                }
 
39308
        }
 
39309
 
 
39310
        DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
 
39311
 
 
39312
        /* no need to compact since we already did that in duk__abandon_array_checked()
 
39313
         * (regardless of whether an array part existed or not.
 
39314
         */
 
39315
 
 
39316
        return;
 
39317
}
 
39318
 
 
39319
/*
 
39320
 *  Object.isSealed() and Object.isFrozen()  (E5 Sections 15.2.3.11, 15.2.3.13)
 
39321
 *
 
39322
 *  Since the algorithms are similar, a helper provides both functions.
 
39323
 *  Freezing is essentially sealing + making plain properties non-writable.
 
39324
 *
 
39325
 *  Note: all virtual (non-concrete) properties are currently non-configurable
 
39326
 *  and non-writable (and there are no accessor virtual properties), so they don't
 
39327
 *  need to be considered here now.
 
39328
 */
 
39329
 
 
39330
int duk_hobject_object_is_sealed_frozen_helper(duk_hobject *obj, int is_frozen) {
 
39331
        duk_uint_fast32_t i;
 
39332
 
 
39333
        DUK_ASSERT(obj != NULL);
 
39334
 
 
39335
        /* Note: no allocation pressure, no need to check refcounts etc */
 
39336
 
 
39337
        /* must not be extensible */
 
39338
        if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
 
39339
                return 0;
 
39340
        }
 
39341
 
 
39342
        /* all virtual properties are non-configurable and non-writable */
 
39343
 
 
39344
        /* entry part must not contain any configurable properties, or
 
39345
         * writable properties (if is_frozen).
 
39346
         */
 
39347
        for (i = 0; i < obj->e_used; i++) {
 
39348
                unsigned int flags;
 
39349
 
 
39350
                if (!DUK_HOBJECT_E_GET_KEY(obj, i)) {
 
39351
                        continue;
 
39352
                }
 
39353
 
 
39354
                /* avoid multiple computations of flags address; bypasses macros */
 
39355
                flags = (unsigned int) DUK_HOBJECT_E_GET_FLAGS(obj, i);
 
39356
 
 
39357
                if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
 
39358
                        return 0;
 
39359
                }
 
39360
                if (is_frozen &&
 
39361
                    !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
 
39362
                    (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
 
39363
                        return 0;
 
39364
                }
 
39365
        }
 
39366
 
 
39367
        /* array part must not contain any non-unused properties, as they would
 
39368
         * be configurable and writable.
 
39369
         */
 
39370
        for (i = 0; i < obj->a_size; i++) {
 
39371
                duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(obj, i);
 
39372
                if (!DUK_TVAL_IS_UNDEFINED_UNUSED(tv)) {
 
39373
                        return 0;
 
39374
                }
 
39375
        }
 
39376
 
 
39377
        return 1;
 
39378
}
 
39379
 
 
39380
/*
 
39381
 *  Object.preventExtensions() and Object.isExtensible()  (E5 Sections 15.2.3.10, 15.2.3.13)
 
39382
 *
 
39383
 *  Implemented directly in macros:
 
39384
 *
 
39385
 *    DUK_HOBJECT_OBJECT_PREVENT_EXTENSIONS()
 
39386
 *    DUK_HOBJECT_OBJECT_IS_EXTENSIBLE()
 
39387
 */
 
39388
 
 
39389
/* Undefine local defines */
 
39390
 
 
39391
#undef DUK__NO_ARRAY_INDEX
 
39392
#undef DUK__HASH_INITIAL
 
39393
#undef DUK__HASH_PROBE_STEP
 
39394
#undef DUK__HASH_UNUSED
 
39395
#undef DUK__HASH_DELETED
 
39396
#undef DUK__VALSTACK_SPACE
 
39397
 
 
39398
#line 1 "duk_hstring_misc.c"
 
39399
/*
 
39400
 *  Misc support functions
 
39401
 */
 
39402
 
 
39403
/* include removed: duk_internal.h */
 
39404
 
 
39405
duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_int_t pos) {
 
39406
        duk_uint32_t boff;
 
39407
        duk_uint8_t *p, *p_start, *p_end;
 
39408
        duk_ucodepoint_t cp;
 
39409
 
 
39410
        /* Caller must check character offset to be inside the string. */
 
39411
        DUK_ASSERT(thr != NULL);
 
39412
        DUK_ASSERT(h != NULL);
 
39413
        DUK_ASSERT(pos >= 0);
 
39414
        DUK_ASSERT(pos < DUK_HSTRING_GET_CHARLEN(h));
 
39415
 
 
39416
        boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
 
39417
        DUK_DDDPRINT("charCodeAt: pos=%d -> boff=%d, str=%!O", pos, boff, h);
 
39418
        DUK_ASSERT_DISABLE(boff >= 0);
 
39419
        DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
 
39420
 
 
39421
        p_start = DUK_HSTRING_GET_DATA(h);
 
39422
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
 
39423
        p = p_start + boff;
 
39424
        DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p", (void *) p_start, (void *) p_end, (void *) p);
 
39425
 
 
39426
        /* This may throw an error though not for valid E5 strings. */
 
39427
        cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
 
39428
        return cp;
 
39429
}
 
39430
#line 1 "duk_hthread_alloc.c"
 
39431
/*
 
39432
 *  duk_hthread allocation and freeing.
 
39433
 */
 
39434
 
 
39435
/* include removed: duk_internal.h */
 
39436
 
 
39437
/*
 
39438
 *  Allocate initial stacks for a thread.  Note that 'thr' must be reachable
 
39439
 *  as a garbage collection may be triggered by the allocation attempts.
 
39440
 *  Returns zero (without leaking memory) if init fails.
 
39441
 */
 
39442
 
 
39443
int duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
 
39444
        size_t alloc_size;
 
39445
        int i;
 
39446
 
 
39447
        DUK_ASSERT(heap != NULL);
 
39448
        DUK_ASSERT(thr != NULL);
 
39449
        DUK_ASSERT(thr->valstack == NULL);
 
39450
        DUK_ASSERT(thr->valstack_end == NULL);
 
39451
        DUK_ASSERT(thr->valstack_bottom == NULL);
 
39452
        DUK_ASSERT(thr->valstack_top == NULL);
 
39453
        DUK_ASSERT(thr->callstack == NULL);
 
39454
        DUK_ASSERT(thr->catchstack == NULL);
 
39455
 
 
39456
        /* valstack */
 
39457
        alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
 
39458
        thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
 
39459
        if (!thr->valstack) {
 
39460
                goto fail;
 
39461
        }
 
39462
        DUK_MEMZERO(thr->valstack, alloc_size);
 
39463
        thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
 
39464
        thr->valstack_bottom = thr->valstack;
 
39465
        thr->valstack_top = thr->valstack;
 
39466
 
 
39467
        for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
 
39468
                DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->valstack[i]);
 
39469
        }
 
39470
 
 
39471
        /* callstack */
 
39472
        alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
 
39473
        thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
 
39474
        if (!thr->callstack) {
 
39475
                goto fail;
 
39476
        }
 
39477
        DUK_MEMZERO(thr->callstack, alloc_size);
 
39478
        thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
 
39479
        DUK_ASSERT(thr->callstack_top == 0);
 
39480
 
 
39481
        /* catchstack */
 
39482
        alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
 
39483
        thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
 
39484
        if (!thr->catchstack) {
 
39485
                goto fail;
 
39486
        }
 
39487
        DUK_MEMZERO(thr->catchstack, alloc_size);
 
39488
        thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
 
39489
        DUK_ASSERT(thr->catchstack_top == 0);
 
39490
 
 
39491
        return 1;
 
39492
 
 
39493
 fail:
 
39494
        DUK_FREE(heap, thr->valstack);
 
39495
        DUK_FREE(heap, thr->callstack);
 
39496
        DUK_FREE(heap, thr->catchstack);
 
39497
 
 
39498
        thr->valstack = NULL;
 
39499
        thr->callstack = NULL;
 
39500
        thr->catchstack = NULL;
 
39501
        return 0;
 
39502
}
 
39503
 
 
39504
/* For indirect allocs. */
 
39505
 
 
39506
void *duk_hthread_get_valstack_ptr(void *ud) {
 
39507
        duk_hthread *thr = (duk_hthread *) ud;
 
39508
        return (void *) thr->valstack;
 
39509
}
 
39510
 
 
39511
void *duk_hthread_get_callstack_ptr(void *ud) {
 
39512
        duk_hthread *thr = (duk_hthread *) ud;
 
39513
        return (void *) thr->callstack;
 
39514
}
 
39515
 
 
39516
void *duk_hthread_get_catchstack_ptr(void *ud) {
 
39517
        duk_hthread *thr = (duk_hthread *) ud;
 
39518
        return (void *) thr->catchstack;
 
39519
}
 
39520
 
 
39521
#line 1 "duk_hthread_builtins.c"
 
39522
/*
 
39523
 *  Initialize built-in objects.  Current thread must have a valstack
 
39524
 *  and initialization errors may longjmp, so a setjmp() catch point
 
39525
 *  must exist.
 
39526
 */
 
39527
 
 
39528
/* include removed: duk_internal.h */
 
39529
 
 
39530
/*
 
39531
 *  Encoding constants, must match genbuiltins.py
 
39532
 */
 
39533
 
 
39534
#define DUK__CLASS_BITS                  5
 
39535
#define DUK__BIDX_BITS                   6
 
39536
#define DUK__STRIDX_BITS                 9  /* FIXME: try to optimize to 8 */
 
39537
#define DUK__NATIDX_BITS                 8
 
39538
#define DUK__NUM_NORMAL_PROPS_BITS       6
 
39539
#define DUK__NUM_FUNC_PROPS_BITS         6
 
39540
#define DUK__PROP_FLAGS_BITS             3
 
39541
#define DUK__STRING_LENGTH_BITS          8
 
39542
#define DUK__STRING_CHAR_BITS            7
 
39543
#define DUK__LENGTH_PROP_BITS            3
 
39544
#define DUK__NARGS_BITS                  3
 
39545
#define DUK__PROP_TYPE_BITS              3
 
39546
#define DUK__MAGIC_BITS                  16
 
39547
 
 
39548
#define DUK__NARGS_VARARGS_MARKER        0x07
 
39549
#define DUK__NO_CLASS_MARKER             0x00   /* 0 = DUK_HOBJECT_CLASS_UNUSED */
 
39550
#define DUK__NO_BIDX_MARKER              0x3f
 
39551
#define DUK__NO_STRIDX_MARKER            0xff
 
39552
 
 
39553
#define DUK__PROP_TYPE_DOUBLE            0
 
39554
#define DUK__PROP_TYPE_STRING            1
 
39555
#define DUK__PROP_TYPE_STRIDX            2
 
39556
#define DUK__PROP_TYPE_BUILTIN           3
 
39557
#define DUK__PROP_TYPE_UNDEFINED         4
 
39558
#define DUK__PROP_TYPE_BOOLEAN_TRUE      5
 
39559
#define DUK__PROP_TYPE_BOOLEAN_FALSE     6
 
39560
#define DUK__PROP_TYPE_ACCESSOR          7
 
39561
 
 
39562
/*
 
39563
 *  Create built-in objects by parsing an init bitstream generated
 
39564
 *  by genbuiltins.py.
 
39565
 */
 
39566
 
 
39567
void duk_hthread_create_builtin_objects(duk_hthread *thr) {
 
39568
        duk_context *ctx = (duk_context *) thr;
 
39569
        duk_bitdecoder_ctx bd_ctx;
 
39570
        duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
 
39571
        duk_hobject *h;
 
39572
        int i, j;
 
39573
 
 
39574
        DUK_DPRINT("INITBUILTINS BEGIN");
 
39575
 
 
39576
        DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
 
39577
        bd->data = (const duk_uint8_t *) duk_builtins_data;
 
39578
        bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
 
39579
 
 
39580
        /*
 
39581
         *  First create all built-in bare objects on the empty valstack.
 
39582
         *  During init, their indices will correspond to built-in indices.
 
39583
         *
 
39584
         *  Built-ins will be reachable from both valstack and thr->builtins.
 
39585
         */
 
39586
 
 
39587
        /* XXX: there is no need to resize valstack because builtin count
 
39588
         * is much less than the default space; assert for it.
 
39589
         */
 
39590
 
 
39591
        DUK_DDPRINT("create empty built-ins");
 
39592
        DUK_ASSERT_TOP(ctx, 0);
 
39593
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
39594
                int class_num;
 
39595
                int len = -1;
 
39596
 
 
39597
                class_num = duk_bd_decode(bd, DUK__CLASS_BITS);
 
39598
                len = duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
 
39599
 
 
39600
                if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
 
39601
                        int natidx;
 
39602
                        int stridx;
 
39603
                        int c_nargs;
 
39604
                        duk_c_function c_func;
 
39605
                        duk_int16_t magic;
 
39606
 
 
39607
                        DUK_DDDPRINT("len=%d", len);
 
39608
                        DUK_ASSERT(len >= 0);
 
39609
 
 
39610
                        natidx = duk_bd_decode(bd, DUK__NATIDX_BITS);
 
39611
                        stridx = duk_bd_decode(bd, DUK__STRIDX_BITS);
 
39612
                        c_func = duk_bi_native_functions[natidx];
 
39613
 
 
39614
                        c_nargs = duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
 
39615
                        if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
 
39616
                                c_nargs = DUK_VARARGS;
 
39617
                        }
 
39618
 
 
39619
                        /* FIXME: set magic directly here? (it could share the c_nargs arg) */
 
39620
                        duk_push_c_function_nospecial(ctx, c_func, c_nargs);
 
39621
 
 
39622
                        h = duk_require_hobject(ctx, -1);
 
39623
                        DUK_ASSERT(h != NULL);
 
39624
 
 
39625
                        /* Currently all built-in native functions are strict.
 
39626
                         * duk_push_c_function() now sets strict flag, so
 
39627
                         * assert for it.
 
39628
                         */
 
39629
                        DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
 
39630
 
 
39631
                        /* FIXME: function properties */
 
39632
 
 
39633
                        duk_push_hstring_stridx(ctx, stridx);
 
39634
                        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
 
39635
 
 
39636
                        /* Almost all global level Function objects are constructable
 
39637
                         * but not all: Function.prototype is a non-constructable,
 
39638
                         * callable Function.
 
39639
                         */
 
39640
                        if (duk_bd_decode_flag(bd)) {
 
39641
                                DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
 
39642
                        } else {
 
39643
                                DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
 
39644
                        }
 
39645
 
 
39646
                        /* Cast converts magic to 16-bit signed value */
 
39647
                        magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
 
39648
                        ((duk_hnativefunction *) h)->magic = magic;
 
39649
                } else {
 
39650
                        /* FIXME: ARRAY_PART for Array prototype? */
 
39651
 
 
39652
                        duk_push_object_helper(ctx,
 
39653
                                               DUK_HOBJECT_FLAG_EXTENSIBLE,
 
39654
                                               -1);  /* no prototype or class yet */
 
39655
 
 
39656
                        h = duk_require_hobject(ctx, -1);
 
39657
                        DUK_ASSERT(h != NULL);
 
39658
                }
 
39659
 
 
39660
                DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
 
39661
 
 
39662
                thr->builtins[i] = h;
 
39663
                DUK_HOBJECT_INCREF(thr, &h->hdr);
 
39664
 
 
39665
                if (len >= 0) {
 
39666
                        /*
 
39667
                         *  For top-level objects, 'length' property has the following
 
39668
                         *  default attributes: non-writable, non-enumerable, non-configurable
 
39669
                         *  (E5 Section 15).
 
39670
                         *
 
39671
                         *  However, 'length' property for Array.prototype has attributes
 
39672
                         *  expected of an Array instance which are different: writable,
 
39673
                         *  non-enumerable, non-configurable (E5 Section 15.4.5.2).
 
39674
                         *
 
39675
                         *  This is currently determined implicitly based on class; there are
 
39676
                         *  no attribute flags in the init data.
 
39677
                         */
 
39678
 
 
39679
                        duk_push_int(ctx, len);
 
39680
                        duk_def_prop_stridx(ctx,
 
39681
                                            -2,
 
39682
                                            DUK_STRIDX_LENGTH,
 
39683
                                            (class_num == DUK_HOBJECT_CLASS_ARRAY ?  /* only Array.prototype matches */
 
39684
                                             DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
 
39685
                }
 
39686
 
 
39687
                /* enable special behaviors last */
 
39688
 
 
39689
                if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
 
39690
                        DUK_HOBJECT_SET_SPECIAL_ARRAY(h);
 
39691
                }
 
39692
                if (class_num == DUK_HOBJECT_CLASS_STRING) {
 
39693
                        DUK_HOBJECT_SET_SPECIAL_STRINGOBJ(h);
 
39694
                }
 
39695
 
 
39696
                /* some assertions */
 
39697
 
 
39698
                DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
 
39699
                /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
 
39700
                DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
 
39701
                DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
 
39702
                /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
 
39703
                DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
 
39704
                DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h));       /* currently, even for Array.prototype */
 
39705
                /* DUK_HOBJECT_FLAG_STRICT varies */
 
39706
                DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) ||  /* all native functions have NEWENV */
 
39707
                           DUK_HOBJECT_HAS_NEWENV(h));
 
39708
                DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
 
39709
                DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
 
39710
                DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
 
39711
                /* DUK_HOBJECT_FLAG_SPECIAL_ARRAY varies */
 
39712
                /* DUK_HOBJECT_FLAG_SPECIAL_STRINGOBJ varies */
 
39713
                DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(h));
 
39714
 
 
39715
                DUK_DDDPRINT("created built-in %d, class=%d, length=%d", i, class_num, len);
 
39716
        }
 
39717
 
 
39718
        /*
 
39719
         *  Then decode the builtins init data (see genbuiltins.py) to
 
39720
         *  init objects
 
39721
         */
 
39722
 
 
39723
        DUK_DDPRINT("initialize built-in object properties");
 
39724
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
39725
                unsigned char t;
 
39726
                int num;
 
39727
 
 
39728
                DUK_DDDPRINT("initializing built-in object at index %d", i);
 
39729
                h = thr->builtins[i];
 
39730
 
 
39731
                t = duk_bd_decode(bd, DUK__BIDX_BITS);
 
39732
                if (t != DUK__NO_BIDX_MARKER) {
 
39733
                        DUK_DDDPRINT("set internal prototype: built-in %d", (int) t);
 
39734
                        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[t]);
 
39735
                }
 
39736
 
 
39737
                t = duk_bd_decode(bd, DUK__BIDX_BITS);
 
39738
                if (t != DUK__NO_BIDX_MARKER) {
 
39739
                        /* 'prototype' property for all built-in objects (which have it) has attributes:
 
39740
                         *  [[Writable]] = false,
 
39741
                         *  [[Enumerable]] = false,
 
39742
                         *  [[Configurable]] = false
 
39743
                         */
 
39744
                        DUK_DDDPRINT("set external prototype: built-in %d", (int) t);
 
39745
                        duk_def_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
 
39746
                }
 
39747
 
 
39748
                t = duk_bd_decode(bd, DUK__BIDX_BITS);
 
39749
                if (t != DUK__NO_BIDX_MARKER) {
 
39750
                        /* 'constructor' property for all built-in objects (which have it) has attributes:
 
39751
                         *  [[Writable]] = true,
 
39752
                         *  [[Enumerable]] = false,     
 
39753
                         *  [[Configurable]] = true
 
39754
                         */
 
39755
                        DUK_DDDPRINT("set external constructor: built-in %d", (int) t);
 
39756
                        duk_def_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
 
39757
                }
 
39758
 
 
39759
                /* normal valued properties */
 
39760
                num = duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
 
39761
                DUK_DDDPRINT("built-in object %d, %d normal valued properties", i, num);
 
39762
                for (j = 0; j < num; j++) {
 
39763
                        int stridx;
 
39764
                        int prop_flags;
 
39765
 
 
39766
                        stridx = duk_bd_decode(bd, DUK__STRIDX_BITS);
 
39767
 
 
39768
                        /*
 
39769
                         *  Property attribute defaults are defined in E5 Section 15 (first
 
39770
                         *  few pages); there is a default for all properties and a special
 
39771
                         *  default for 'length' properties.  Variation from the defaults is
 
39772
                         *  signaled using a single flag bit in the bitstream.
 
39773
                         */
 
39774
 
 
39775
                        if (duk_bd_decode_flag(bd)) {
 
39776
                                prop_flags = duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
 
39777
                        } else {
 
39778
                                if (stridx == DUK_STRIDX_LENGTH) {
 
39779
                                        prop_flags = DUK_PROPDESC_FLAGS_NONE;
 
39780
                                } else {
 
39781
                                        prop_flags = DUK_PROPDESC_FLAGS_WC;
 
39782
                                }
 
39783
                        }
 
39784
 
 
39785
                        t = duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
 
39786
 
 
39787
                        DUK_DDDPRINT("built-in %d, normal-valued property %d, stridx %d, flags 0x%02x, type %d",
 
39788
                                     i, j, stridx, prop_flags, (int) t);
 
39789
 
 
39790
                        switch (t) {
 
39791
                        case DUK__PROP_TYPE_DOUBLE: {
 
39792
                                duk_double_union du;
 
39793
                                int k;
 
39794
 
 
39795
                                for (k = 0; k < 8; k++) {
 
39796
                                        /* Encoding endianness must match target memory layout,
 
39797
                                         * build scripts and genbuiltins.py must ensure this.
 
39798
                                         */
 
39799
                                        du.uc[k] = (duk_uint8_t) duk_bd_decode(bd, 8);
 
39800
                                }
 
39801
 
 
39802
                                duk_push_number(ctx, du.d);  /* push operation normalizes NaNs */
 
39803
                                break;
 
39804
                        }
 
39805
                        case DUK__PROP_TYPE_STRING: {
 
39806
                                int n;
 
39807
                                int k;
 
39808
                                char *p;
 
39809
 
 
39810
                                n = duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
 
39811
                                p = (char *) duk_push_fixed_buffer(ctx, n);
 
39812
                                for (k = 0; k < n; k++) {
 
39813
                                        *p++ = duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
 
39814
                                }
 
39815
 
 
39816
                                duk_to_string(ctx, -1);
 
39817
                                break;
 
39818
                        }
 
39819
                        case DUK__PROP_TYPE_STRIDX: {
 
39820
                                int n;
 
39821
 
 
39822
                                n = duk_bd_decode(bd, DUK__STRIDX_BITS);
 
39823
                                DUK_ASSERT(n >= 0 && n < DUK_HEAP_NUM_STRINGS);
 
39824
                                duk_push_hstring_stridx(ctx, n);
 
39825
                                break;
 
39826
                        }
 
39827
                        case DUK__PROP_TYPE_BUILTIN: {
 
39828
                                int bidx;
 
39829
 
 
39830
                                bidx = duk_bd_decode(bd, DUK__BIDX_BITS);
 
39831
                                DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
 
39832
                                duk_dup(ctx, bidx);
 
39833
                                break;
 
39834
                        }
 
39835
                        case DUK__PROP_TYPE_UNDEFINED: {
 
39836
                                duk_push_undefined(ctx);
 
39837
                                break;
 
39838
                        }
 
39839
                        case DUK__PROP_TYPE_BOOLEAN_TRUE: {
 
39840
                                duk_push_true(ctx);
 
39841
                                break;
 
39842
                        }
 
39843
                        case DUK__PROP_TYPE_BOOLEAN_FALSE: {
 
39844
                                duk_push_false(ctx);
 
39845
                                break;
 
39846
                        }
 
39847
                        case DUK__PROP_TYPE_ACCESSOR: {
 
39848
                                int natidx_getter = duk_bd_decode(bd, DUK__NATIDX_BITS);
 
39849
                                int natidx_setter = duk_bd_decode(bd, DUK__NATIDX_BITS);
 
39850
                                duk_c_function c_func_getter;
 
39851
                                duk_c_function c_func_setter;
 
39852
 
 
39853
                                /* XXX: this is a bit awkward because there is no exposed helper
 
39854
                                 * in the API style, only this internal helper.
 
39855
                                 */
 
39856
                                DUK_DDDPRINT("built-in accessor property: objidx=%d, stridx=%d, getteridx=%d, setteridx=%d, flags=0x%04x",
 
39857
                                             i, stridx, natidx_getter, natidx_setter, prop_flags);
 
39858
 
 
39859
                                c_func_getter = duk_bi_native_functions[natidx_getter];
 
39860
                                c_func_setter = duk_bi_native_functions[natidx_setter];
 
39861
                                duk_push_c_function_noconstruct_nospecial(ctx, c_func_getter, 0);  /* always 0 args */
 
39862
                                duk_push_c_function_noconstruct_nospecial(ctx, c_func_setter, 1);  /* always 1 arg */
 
39863
 
 
39864
                                /* FIXME: magic for getter/setter? */
 
39865
 
 
39866
                                prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR;  /* accessor flag not encoded explicitly */
 
39867
                                duk_hobject_define_accessor_internal(thr,
 
39868
                                                                     duk_require_hobject(ctx, i),
 
39869
                                                                     DUK_HTHREAD_GET_STRING(thr, stridx),
 
39870
                                                                     duk_require_hobject(ctx, -2),
 
39871
                                                                     duk_require_hobject(ctx, -1),
 
39872
                                                                     prop_flags);
 
39873
                                duk_pop_2(ctx);  /* getter and setter, now reachable through object */
 
39874
                                goto skip_value;
 
39875
                        }
 
39876
                        default: {
 
39877
                                /* exhaustive */
 
39878
                                DUK_UNREACHABLE();
 
39879
                        }
 
39880
                        }
 
39881
 
 
39882
                        DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
 
39883
                        duk_def_prop_stridx(ctx, i, stridx, prop_flags);
 
39884
 
 
39885
                 skip_value:
 
39886
                        continue;  /* avoid empty label at the end of a compound statement */
 
39887
                }
 
39888
 
 
39889
                /* native function properties */
 
39890
                num = duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
 
39891
                DUK_DDDPRINT("built-in object %d, %d function valued properties", i, num);
 
39892
                for (j = 0; j < num; j++) {
 
39893
                        int stridx;
 
39894
                        int natidx;
 
39895
                        int c_nargs;
 
39896
                        int c_length;
 
39897
                        duk_int16_t magic;
 
39898
                        duk_c_function c_func;
 
39899
                        duk_hnativefunction *h_func;
 
39900
 
 
39901
                        stridx = duk_bd_decode(bd, DUK__STRIDX_BITS);
 
39902
                        natidx = duk_bd_decode(bd, DUK__NATIDX_BITS);
 
39903
 
 
39904
                        c_length = duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
 
39905
                        c_nargs = duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
 
39906
                        if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
 
39907
                                c_nargs = DUK_VARARGS;
 
39908
                        }
 
39909
 
 
39910
                        c_func = duk_bi_native_functions[natidx];
 
39911
 
 
39912
                        DUK_DDDPRINT("built-in %d, function-valued property %d, stridx %d, natidx %d, length %d, nargs %d",
 
39913
                                     i, j, stridx, natidx, c_length, (c_nargs == DUK_VARARGS ? -1 : c_nargs));
 
39914
 
 
39915
                        /* [ (builtin objects) ] */
 
39916
 
 
39917
                        duk_push_c_function_noconstruct_nospecial(ctx, c_func, c_nargs);
 
39918
                        h_func = duk_require_hnativefunction(ctx, -1);
 
39919
                        DUK_UNREF(h_func);
 
39920
 
 
39921
                        /* Currently all built-in native functions are strict.
 
39922
                         * This doesn't matter for many functions, but e.g.
 
39923
                         * String.prototype.charAt (and other string functions)
 
39924
                         * rely on being strict so that their 'this' binding is
 
39925
                         * not automatically coerced.
 
39926
                         */
 
39927
                        DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
 
39928
 
 
39929
                        /* No built-in functions are constructable except the top
 
39930
                         * level ones (Number, etc).
 
39931
                         */
 
39932
                        DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
 
39933
 
 
39934
                        /* FIXME: any way to avoid decoding magic bit; there are quite
 
39935
                         * many function properties and relatively few with magic values.
 
39936
                         */
 
39937
                        /* Cast converts magic to 16-bit signed value */
 
39938
                        magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
 
39939
                        h_func->magic = magic;
 
39940
 
 
39941
                        /* [ (builtin objects) func ] */
 
39942
 
 
39943
                        duk_push_int(ctx, c_length);
 
39944
                        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
 
39945
 
 
39946
                        duk_push_hstring_stridx(ctx, stridx);
 
39947
                        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
 
39948
 
 
39949
                        /* FIXME: other properties of function instances; 'arguments', 'caller'. */
 
39950
 
 
39951
                        DUK_DDPRINT("built-in object %d, function property %d -> %!T", i, j, duk_get_tval(ctx, -1));
 
39952
 
 
39953
                        /* [ (builtin objects) func ] */
 
39954
 
 
39955
                        /*
 
39956
                         *  The default property attributes are correct for all
 
39957
                         *  function valued properties of built-in objects now.
 
39958
                         */
 
39959
 
 
39960
                        duk_def_prop_stridx(ctx, i, stridx, DUK_PROPDESC_FLAGS_WC);
 
39961
 
 
39962
                        /* [ (builtin objects) ] */
 
39963
                }
 
39964
        }
 
39965
 
 
39966
        /*
 
39967
         *  Special post-tweaks, for cases not covered by the init data format.
 
39968
         *
 
39969
         *  - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
 
39970
         *    toGMTString is required to have the same Function object as
 
39971
         *    toUTCString in E5 Section B.2.6.  Note that while Smjs respects
 
39972
         *    this, V8 does not (the Function objects are distinct).
 
39973
         *
 
39974
         *  - Make DoubleError non-extensible.
 
39975
         *
 
39976
         *  - Add info about most important effective compile options to Duktape.
 
39977
         */
 
39978
 
 
39979
        duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
 
39980
        duk_def_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
 
39981
 
 
39982
        h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
 
39983
        DUK_ASSERT(h != NULL);
 
39984
        DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
 
39985
 
 
39986
        duk_push_string(ctx,
 
39987
#if defined(DUK_USE_INTEGER_LE)
 
39988
                        "l"
 
39989
#elif defined(DUK_USE_INTEGER_BE)
 
39990
                        "b"
 
39991
#elif defined(DUK_USE_INTEGER_ME)  /* integer mixed endian not really used now */
 
39992
                        "m"
 
39993
#else
 
39994
                        "?"
 
39995
#endif
 
39996
#if defined(DUK_USE_DOUBLE_LE)
 
39997
                        "l"
 
39998
#elif defined(DUK_USE_DOUBLE_BE)
 
39999
                        "b"
 
40000
#elif defined(DUK_USE_DOUBLE_ME)
 
40001
                        "m"
 
40002
#else
 
40003
                        "?"
 
40004
#endif
 
40005
#if defined(DUK_USE_BYTEORDER_FORCED)
 
40006
                        "f"
 
40007
#endif
 
40008
                        " "
 
40009
#if defined(DUK_USE_PACKED_TVAL)
 
40010
                        "p"
 
40011
#else
 
40012
                        "u"
 
40013
#endif
 
40014
                        " "
 
40015
#if defined(DUK_USE_HOBJECT_LAYOUT_1)
 
40016
                        "p1"
 
40017
#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
 
40018
                        "p2"
 
40019
#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
 
40020
                        "p3"
 
40021
#else
 
40022
                        "p?"
 
40023
#endif
 
40024
                        " "
 
40025
#if defined(DUK_USE_ALIGN_4)
 
40026
                        "a4"
 
40027
#elif defined(DUK_USE_ALIGN_8)
 
40028
                        "a8"
 
40029
#else
 
40030
                        "a1"
 
40031
#endif
 
40032
                        " "
 
40033
                        DUK_USE_ARCH_STRING);
 
40034
        duk_def_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
 
40035
 
 
40036
        /*
 
40037
         *  InitJS code - Ecmascript code evaluated from a built-in source
 
40038
         *  which provides e.g. backward compatibility.  User can also provide
 
40039
         *  JS code to be evaluated at startup.
 
40040
         */
 
40041
 
 
40042
#ifdef DUK_USE_INITJS
 
40043
        /* FIXME: compression */
 
40044
        duk_eval_string(ctx, (const char *) duk_initjs_data);  /* initjs data is NUL terminated */
 
40045
        duk_pop(ctx);
 
40046
#endif  /* DUK_USE_INITJS */
 
40047
 
 
40048
#ifdef DUK_USE_USER_INITJS
 
40049
        /* FIXME: compression, at least as an option? */
 
40050
        /* FIXME: unused now */
 
40051
        duk_eval_string(ctx, (const char *) DUK_USE_USER_INITJS);
 
40052
        duk_pop(ctx);
 
40053
#endif  /* DUK_USE_USER_INITJS */
 
40054
 
 
40055
        /*
 
40056
         *  Since built-ins are not often extended, compact them.
 
40057
         */
 
40058
 
 
40059
        DUK_DDPRINT("compact built-ins");
 
40060
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
40061
                duk_hobject_compact_props(thr, thr->builtins[i]);
 
40062
        }
 
40063
 
 
40064
        DUK_DPRINT("INITBUILTINS END");
 
40065
 
 
40066
#ifdef DUK_USE_DDEBUG
 
40067
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
40068
                DUK_DDPRINT("built-in object %d after initialization and compacting: %!@iO", i, thr->builtins[i]);
 
40069
        }
 
40070
#endif
 
40071
        
 
40072
#ifdef DUK_USE_DDDEBUG
 
40073
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
40074
                DUK_DDDPRINT("built-in object %d after initialization and compacting", i);
 
40075
                DUK_DEBUG_DUMP_HOBJECT(thr->builtins[i]);
 
40076
        }
 
40077
#endif
 
40078
 
 
40079
        /*
 
40080
         *  Pop built-ins from stack: they are now INCREF'd and
 
40081
         *  reachable from the builtins[] array.
 
40082
         */
 
40083
 
 
40084
        duk_pop_n(ctx, DUK_NUM_BUILTINS);
 
40085
        DUK_ASSERT_TOP(ctx, 0);
 
40086
}
 
40087
 
 
40088
void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
 
40089
        int i;
 
40090
 
 
40091
        for (i = 0; i < DUK_NUM_BUILTINS; i++) {
 
40092
                thr_to->builtins[i] = thr_from->builtins[i];
 
40093
                DUK_HOBJECT_INCREF(thr_to, thr_to->builtins[i]);  /* side effect free */
 
40094
        }
 
40095
}
 
40096
 
 
40097
#line 1 "duk_hthread_misc.c"
 
40098
/*
 
40099
 *  Thread support.
 
40100
 */
 
40101
 
 
40102
/* include removed: duk_internal.h */
 
40103
 
 
40104
/* FIXME: separate "executor" thread and "target" thread for DECREF?
 
40105
 * This function is a bit dangerous because we free the built-ins and
 
40106
 * DECREF.  If a built-in gets DECREF'd to zero and has a finalizer,
 
40107
 * we might have some problems in the finalizer.
 
40108
 */
 
40109
 
 
40110
void duk_hthread_terminate(duk_hthread *thr) {
 
40111
        DUK_ASSERT(thr != NULL);
 
40112
 
 
40113
        /* Order of unwinding is important */
 
40114
 
 
40115
        duk_hthread_catchstack_unwind(thr, 0);
 
40116
 
 
40117
        duk_hthread_callstack_unwind(thr, 0);  /* side effects, possibly errors */
 
40118
 
 
40119
        thr->valstack_bottom = thr->valstack;
 
40120
        duk_set_top((duk_context *) thr, 0);  /* unwinds valstack, updating refcounts */
 
40121
 
 
40122
        thr->state = DUK_HTHREAD_STATE_TERMINATED;
 
40123
 
 
40124
        /* Here we could remove references to built-ins, but it may not be
 
40125
         * worth the effort because built-ins are quite likely to be shared
 
40126
         * with another (unterminated) thread, and terminated threads are also
 
40127
         * usually garbage collected quite quickly.  Also, doing DECREFs
 
40128
         * could trigger finalization, which would run on the current thread
 
40129
         * and have access to only some of the built-ins.  Garbage collection
 
40130
         * deals with this correctly already.
 
40131
         */
 
40132
 
 
40133
        /* XXX: Shrink the stacks to minimize memory usage?  May not
 
40134
         * be worth the effort because terminated threads are usually
 
40135
         * garbage collected quite soon.
 
40136
         */
 
40137
}
 
40138
 
 
40139
duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
 
40140
        DUK_ASSERT(thr != NULL);
 
40141
 
 
40142
        if (thr->callstack_top > 0) {
 
40143
                return thr->callstack + thr->callstack_top - 1;
 
40144
        } else {
 
40145
                return NULL;
 
40146
        }
 
40147
}
 
40148
 
 
40149
#line 1 "duk_hthread_stacks.c"
 
40150
/*
 
40151
 *  Manipulation of thread stacks (valstack, callstack, catchstack).
 
40152
 *
 
40153
 *  Ideally unwinding of stacks should have no side effects, which would
 
40154
 *  then favor separate unwinding and shrink check primitives for each
 
40155
 *  stack type.  A shrink check may realloc and thus have side effects.
 
40156
 *
 
40157
 *  However, currently callstack unwinding itself has side effects, as it
 
40158
 *  needs to DECREF multiple objects, close environment records, etc.
 
40159
 *  Stacks must thus be unwound in the correct order by the caller.
 
40160
 *
 
40161
 *  (FIXME: This should be probably reworked so that there is a shared
 
40162
 *  unwind primitive which handles all stacks as requested, and knows
 
40163
 *  the proper order for unwinding.)
 
40164
 *
 
40165
 *  Valstack entries above 'top' are always kept initialized to
 
40166
 *  "undefined unused".  Callstack and catchstack entries above 'top'
 
40167
 *  are not zeroed and are left as garbage.
 
40168
 *
 
40169
 *  Value stack handling is mostly a part of the API implementation.
 
40170
 */
 
40171
 
 
40172
/* include removed: duk_internal.h */
 
40173
 
 
40174
/* check that there is space for at least one new entry */
 
40175
void duk_hthread_callstack_grow(duk_hthread *thr) {
 
40176
        duk_size_t old_size;
 
40177
        duk_size_t new_size;
 
40178
 
 
40179
        DUK_ASSERT(thr != NULL);
 
40180
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);   /* avoid warning (unsigned) */
 
40181
        DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
 
40182
 
 
40183
        if (thr->callstack_top < thr->callstack_size) {
 
40184
                return;
 
40185
        }
 
40186
 
 
40187
        old_size = thr->callstack_size;
 
40188
        new_size = old_size + DUK_CALLSTACK_GROW_STEP;
 
40189
 
 
40190
        /* this is a bit approximate (errors out before max is reached); this is OK */
 
40191
        if (new_size >= thr->callstack_max) {
 
40192
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "callstack limit");
 
40193
        }
 
40194
 
 
40195
        DUK_DDPRINT("growing callstack %d -> %d", old_size, new_size);
 
40196
 
 
40197
        /*
 
40198
         *  Note: must use indirect variant of DUK_REALLOC() because underlying
 
40199
         *  pointer may be changed by mark-and-sweep.
 
40200
         */
 
40201
 
 
40202
        thr->callstack = (duk_activation *) DUK_REALLOC_INDIRECT_CHECKED(thr, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
 
40203
        thr->callstack_size = new_size;
 
40204
 
 
40205
        /* note: any entries above the callstack top are garbage and not zeroed */
 
40206
}
 
40207
 
 
40208
void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
 
40209
        duk_size_t new_size;
 
40210
        duk_activation *p;
 
40211
 
 
40212
        DUK_ASSERT(thr != NULL);
 
40213
        DUK_ASSERT_DISABLE(thr->callstack_top >= 0);  /* avoid warning (unsigned) */
 
40214
        DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
 
40215
 
 
40216
        if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
 
40217
                return;
 
40218
        }
 
40219
 
 
40220
        new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
 
40221
        DUK_ASSERT(new_size >= thr->callstack_top);
 
40222
 
 
40223
        DUK_DDPRINT("shrinking callstack %d -> %d", thr->callstack_size, new_size);
 
40224
 
 
40225
        /*
 
40226
         *  Note: must use indirect variant of DUK_REALLOC() because underlying
 
40227
         *  pointer may be changed by mark-and-sweep.
 
40228
         */
 
40229
 
 
40230
        /* shrink failure is not fatal */
 
40231
        p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
 
40232
        if (p) {
 
40233
                thr->callstack = p;
 
40234
                thr->callstack_size = new_size;
 
40235
        } else {
 
40236
                DUK_DPRINT("callstack shrink failed, ignoring");
 
40237
        }
 
40238
 
 
40239
        /* note: any entries above the callstack top are garbage and not zeroed */
 
40240
}
 
40241
 
 
40242
void duk_hthread_callstack_unwind(duk_hthread *thr, int new_top) {
 
40243
        int idx;  /* FIXME: typing of idx and new_top */
 
40244
 
 
40245
        DUK_DDDPRINT("unwind callstack top of thread %p from %d to %d",
 
40246
                     (void *) thr,
 
40247
                     (thr != NULL ? (int) thr->callstack_top : (int) -1),
 
40248
                     (int) new_top);
 
40249
 
 
40250
        DUK_ASSERT(thr);
 
40251
        DUK_ASSERT(thr->heap);
 
40252
        DUK_ASSERT(new_top >= 0);
 
40253
        DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top);  /* cannot grow */
 
40254
 
 
40255
        /*
 
40256
         *  The loop below must avoid issues with potential callstack
 
40257
         *  reallocations.  A resize (and other side effects) may happen
 
40258
         *  e.g. due to finalizer/errhandler calls caused by a refzero or
 
40259
         *  mark-and-sweep.  Arbitrary finalizers may run, because when
 
40260
         *  an environment record is refzero'd, it may refer to arbitrary
 
40261
         *  values which also become refzero'd.
 
40262
         *
 
40263
         *  So, the pointer 'p' is re-looked-up below whenever a side effect
 
40264
         *  might have changed it.
 
40265
         */
 
40266
 
 
40267
        idx = thr->callstack_top;
 
40268
        while (idx > new_top) {
 
40269
                duk_activation *p;
 
40270
#ifdef DUK_USE_REFERENCE_COUNTING
 
40271
                duk_hobject *tmp;
 
40272
#endif
 
40273
 
 
40274
                idx--;
 
40275
                DUK_ASSERT(idx >= 0);
 
40276
                DUK_ASSERT((duk_size_t) idx < thr->callstack_size);  /* true, despite side effect resizes */
 
40277
 
 
40278
                p = &thr->callstack[idx];
 
40279
                DUK_ASSERT(p->func != NULL);
 
40280
 
 
40281
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
40282
                /*
 
40283
                 *  Restore 'caller' property for non-strict callee functions.
 
40284
                 */
 
40285
 
 
40286
                if (!DUK_HOBJECT_HAS_STRICT(p->func)) {
 
40287
                        duk_tval *tv_caller;
 
40288
                        duk_tval tv_tmp;
 
40289
                        duk_hobject *h_tmp;
 
40290
 
 
40291
                        tv_caller = duk_hobject_find_existing_entry_tval_ptr(p->func, DUK_HTHREAD_STRING_CALLER(thr));
 
40292
 
 
40293
                        /* The p->prev_caller should only be set if the entry for 'caller'
 
40294
                         * exists (as it is only set in that case, and the property is not
 
40295
                         * configurable), but handle all the cases anyway.
 
40296
                         */
 
40297
 
 
40298
                        if (tv_caller) {
 
40299
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
 
40300
                                if (p->prev_caller) {
 
40301
                                        /* Just transfer the refcount from p->prev_caller to tv_caller,
 
40302
                                         * so no need for a refcount update.  This is the expected case.
 
40303
                                         */
 
40304
                                        DUK_TVAL_SET_OBJECT(tv_caller, p->prev_caller);
 
40305
                                        p->prev_caller = NULL;
 
40306
                                } else {
 
40307
                                        DUK_TVAL_SET_NULL(tv_caller);   /* no incref needed */
 
40308
                                        DUK_ASSERT(p->prev_caller == NULL);
 
40309
                                }
 
40310
                                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
40311
                        } else {
 
40312
                                h_tmp = p->prev_caller;
 
40313
                                if (h_tmp) {
 
40314
                                        p->prev_caller = NULL;
 
40315
                                        DUK_HOBJECT_DECREF(thr, h_tmp);  /* side effects */
 
40316
                                }
 
40317
                        }
 
40318
                        p = &thr->callstack[idx];  /* avoid side effects */
 
40319
                        DUK_ASSERT(p->prev_caller == NULL);
 
40320
                }
 
40321
#endif
 
40322
 
 
40323
                /*
 
40324
                 *  Close environment record(s) if they exist.
 
40325
                 *
 
40326
                 *  Only variable environments are closed.  If lex_env != var_env, it
 
40327
                 *  cannot currently contain any register bound declarations.
 
40328
                 *
 
40329
                 *  Only environments created for a NEWENV function are closed.  If an
 
40330
                 *  environment is created for e.g. an eval call, it must not be closed.
 
40331
                 */
 
40332
 
 
40333
                if (!DUK_HOBJECT_HAS_NEWENV(p->func)) {
 
40334
                        DUK_DDDPRINT("skip closing environments, envs not owned by this activation");
 
40335
                        goto skip_env_close;
 
40336
                }
 
40337
 
 
40338
                DUK_ASSERT(p->lex_env == p->var_env);
 
40339
                if (p->var_env != NULL) {
 
40340
                        DUK_DDDPRINT("closing var_env record %p -> %!O",
 
40341
                                     (void *) p->var_env, (duk_heaphdr *) p->var_env);
 
40342
                        duk_js_close_environment_record(thr, p->var_env, p->func, p->idx_bottom);
 
40343
                        p = &thr->callstack[idx];  /* avoid side effect issues */
 
40344
                }
 
40345
 
 
40346
#if 0
 
40347
                if (p->lex_env != NULL) {
 
40348
                        if (p->lex_env == p->var_env) {
 
40349
                                /* common case, already closed, so skip */
 
40350
                                DUK_DDPRINT("lex_env and var_env are the same and lex_env "
 
40351
                                            "already closed -> skip closing lex_env");
 
40352
                                ;
 
40353
                        } else {
 
40354
                                DUK_DDPRINT("closing lex_env record %p -> %!O",
 
40355
                                            (void *) p->lex_env, (duk_heaphdr *) p->lex_env);
 
40356
                                duk_js_close_environment_record(thr, p->lex_env, p->func, p->idx_bottom);
 
40357
                                p = &thr->callstack[idx];  /* avoid side effect issues */
 
40358
                        }
 
40359
                }
 
40360
#endif
 
40361
 
 
40362
                DUK_ASSERT((p->lex_env == NULL) ||
 
40363
                           ((duk_hobject_find_existing_entry_tval_ptr(p->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
 
40364
                            (duk_hobject_find_existing_entry_tval_ptr(p->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
 
40365
                            (duk_hobject_find_existing_entry_tval_ptr(p->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
 
40366
                            (duk_hobject_find_existing_entry_tval_ptr(p->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
 
40367
 
 
40368
                DUK_ASSERT((p->var_env == NULL) ||
 
40369
                           ((duk_hobject_find_existing_entry_tval_ptr(p->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
 
40370
                            (duk_hobject_find_existing_entry_tval_ptr(p->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
 
40371
                            (duk_hobject_find_existing_entry_tval_ptr(p->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
 
40372
                            (duk_hobject_find_existing_entry_tval_ptr(p->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
 
40373
 
 
40374
         skip_env_close:
 
40375
 
 
40376
                /*
 
40377
                 *  Update preventcount
 
40378
                 */
 
40379
 
 
40380
                if (p->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
 
40381
                        DUK_ASSERT(thr->callstack_preventcount >= 1);
 
40382
                        thr->callstack_preventcount--;
 
40383
                }
 
40384
 
 
40385
                /*
 
40386
                 *  Reference count updates
 
40387
                 *
 
40388
                 *  Note: careful manipulation of refcounts.  The top is
 
40389
                 *  not updated yet, so all the activations are reachable
 
40390
                 *  for mark-and-sweep (which may be triggered by decref).
 
40391
                 *  However, the pointers are NULL so this is not an issue.
 
40392
                 */
 
40393
 
 
40394
#ifdef DUK_USE_REFERENCE_COUNTING
 
40395
                tmp = p->var_env;
 
40396
#endif
 
40397
                p->var_env = NULL;
 
40398
#ifdef DUK_USE_REFERENCE_COUNTING
 
40399
                DUK_HOBJECT_DECREF(thr, tmp);
 
40400
                p = &thr->callstack[idx];  /* avoid side effect issues */
 
40401
#endif
 
40402
 
 
40403
#ifdef DUK_USE_REFERENCE_COUNTING
 
40404
                tmp = p->lex_env;
 
40405
#endif
 
40406
                p->lex_env = NULL;
 
40407
#ifdef DUK_USE_REFERENCE_COUNTING
 
40408
                DUK_HOBJECT_DECREF(thr, tmp);
 
40409
                p = &thr->callstack[idx];  /* avoid side effect issues */
 
40410
#endif
 
40411
 
 
40412
                /* Note: this may cause a corner case situation where a finalizer
 
40413
                 * may see a currently reachable activation whose 'func' is NULL.
 
40414
                 */
 
40415
#ifdef DUK_USE_REFERENCE_COUNTING
 
40416
                tmp = p->func;
 
40417
#endif
 
40418
                p->func = NULL;
 
40419
#ifdef DUK_USE_REFERENCE_COUNTING
 
40420
                DUK_HOBJECT_DECREF(thr, tmp);
 
40421
                p = &thr->callstack[idx];  /* avoid side effect issues */
 
40422
                DUK_UNREF(p);
 
40423
#endif
 
40424
        }
 
40425
 
 
40426
        thr->callstack_top = new_top;
 
40427
 
 
40428
        /*
 
40429
         *  We could clear the book-keeping variables for the topmost activation,
 
40430
         *  but don't do so now.
 
40431
         */
 
40432
#if 0
 
40433
        if (thr->callstack_top > 0) {
 
40434
                duk_activation *p = thr->callstack + thr->callstack_top - 1;
 
40435
                p->idx_retval = -1;
 
40436
        }
 
40437
#endif
 
40438
 
 
40439
        /* Note: any entries above the callstack top are garbage and not zeroed.
 
40440
         * Also topmost activation idx_retval is garbage and not zeroed.
 
40441
         */
 
40442
}
 
40443
 
 
40444
void duk_hthread_catchstack_grow(duk_hthread *thr) {
 
40445
        duk_size_t old_size;
 
40446
        duk_size_t new_size;
 
40447
 
 
40448
        DUK_ASSERT(thr != NULL);
 
40449
        DUK_ASSERT_DISABLE(thr->catchstack_top);  /* avoid warning (unsigned) */
 
40450
        DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
 
40451
 
 
40452
        if (thr->catchstack_top < thr->catchstack_size) {
 
40453
                return;
 
40454
        }
 
40455
 
 
40456
        old_size = thr->catchstack_size;
 
40457
        new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
 
40458
 
 
40459
        /* this is a bit approximate (errors out before max is reached); this is OK */
 
40460
        if (new_size >= thr->catchstack_max) {
 
40461
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "catchstack limit");
 
40462
        }
 
40463
 
 
40464
        DUK_DDPRINT("growing catchstack %d -> %d", old_size, new_size);
 
40465
 
 
40466
        /*
 
40467
         *  Note: must use indirect variant of DUK_REALLOC() because underlying
 
40468
         *  pointer may be changed by mark-and-sweep.
 
40469
         */
 
40470
 
 
40471
        thr->catchstack = (duk_catcher *) DUK_REALLOC_INDIRECT_CHECKED(thr, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
 
40472
        thr->catchstack_size = new_size;
 
40473
 
 
40474
        /* note: any entries above the catchstack top are garbage and not zeroed */
 
40475
}
 
40476
 
 
40477
void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
 
40478
        duk_size_t new_size;
 
40479
        duk_catcher *p;
 
40480
 
 
40481
        DUK_ASSERT(thr != NULL);
 
40482
        DUK_ASSERT_DISABLE(thr->catchstack_top >= 0);  /* avoid warning (unsigned) */
 
40483
        DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
 
40484
 
 
40485
        if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
 
40486
                return;
 
40487
        }
 
40488
 
 
40489
        new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
 
40490
        DUK_ASSERT(new_size >= thr->catchstack_top);
 
40491
 
 
40492
        DUK_DDPRINT("shrinking catchstack %d -> %d", thr->catchstack_size, new_size);
 
40493
 
 
40494
        /*
 
40495
         *  Note: must use indirect variant of DUK_REALLOC() because underlying
 
40496
         *  pointer may be changed by mark-and-sweep.
 
40497
         */
 
40498
 
 
40499
        /* shrink failure is not fatal */
 
40500
        p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
 
40501
        if (p) {
 
40502
                thr->catchstack = p;
 
40503
                thr->catchstack_size = new_size;
 
40504
        } else {
 
40505
                DUK_DPRINT("catchstack shrink failed, ignoring");
 
40506
        }
 
40507
 
 
40508
        /* note: any entries above the catchstack top are garbage and not zeroed */
 
40509
}
 
40510
 
 
40511
void duk_hthread_catchstack_unwind(duk_hthread *thr, int new_top) {
 
40512
        int idx;  /* FIXME: typing of 'new_top' and 'idx' */
 
40513
 
 
40514
        DUK_DDDPRINT("unwind catchstack top of thread %p from %d to %d",
 
40515
                     (void *) thr,
 
40516
                     (thr != NULL ? (int) thr->catchstack_top : (int) -1),
 
40517
                     (int) new_top);
 
40518
 
 
40519
        DUK_ASSERT(thr);
 
40520
        DUK_ASSERT(thr->heap);
 
40521
        DUK_ASSERT(new_top >= 0);
 
40522
        DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top);  /* cannot grow */
 
40523
 
 
40524
        /*
 
40525
         *  Since there are no references in the catcher structure,
 
40526
         *  unwinding is quite simple.  The only thing we need to
 
40527
         *  look out for is popping a possible lexical environment
 
40528
         *  established for an active catch clause.
 
40529
         */
 
40530
 
 
40531
        idx = thr->catchstack_top;
 
40532
        while (idx > new_top) {
 
40533
                duk_catcher *p;
 
40534
                duk_activation *act;
 
40535
                duk_hobject *env;
 
40536
 
 
40537
                idx--;
 
40538
                DUK_ASSERT(idx >= 0);
 
40539
                DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
 
40540
 
 
40541
                p = &thr->catchstack[idx];
 
40542
 
 
40543
                if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
 
40544
                        DUK_DDDPRINT("unwinding catchstack idx %d, callstack idx %d, callstack top %d: lexical environment active",
 
40545
                                     idx, p->callstack_index, thr->callstack_top);
 
40546
 
 
40547
                        /* FIXME: Here we have a nasty dependency: the need to manipulate
 
40548
                         * the callstack means that catchstack must always be unwound by
 
40549
                         * the caller before unwinding the callstack.  This should be fixed
 
40550
                         * later.
 
40551
                         */
 
40552
 
 
40553
                        /* Note that multiple catchstack entries may refer to the same
 
40554
                         * callstack entry.
 
40555
                         */
 
40556
                        act = &thr->callstack[p->callstack_index];
 
40557
                        DUK_ASSERT(act >= thr->callstack);
 
40558
                        DUK_ASSERT(act < &thr->callstack[thr->callstack_top]);
 
40559
 
 
40560
                        DUK_DDDPRINT("catchstack_index=%d, callstack_index=%d, lex_env=%!iO",
 
40561
                                     (int) idx, (int) p->callstack_index, act->lex_env);
 
40562
 
 
40563
                        env = act->lex_env;             /* current lex_env of the activation (created for catcher) */
 
40564
                        DUK_ASSERT(env != NULL);        /* must be, since env was created when catcher was created */
 
40565
                        act->lex_env = env->prototype;  /* prototype is lex_env before catcher created */
 
40566
                        DUK_HOBJECT_DECREF(thr, env);
 
40567
 
 
40568
                        /* There is no need to decref anything else than 'env': if 'env'
 
40569
                         * becomes unreachable, refzero will handle decref'ing its prototype.
 
40570
                         */
 
40571
                }
 
40572
        }
 
40573
 
 
40574
        thr->catchstack_top = new_top;
 
40575
 
 
40576
        /* note: any entries above the catchstack top are garbage and not zeroed */
 
40577
}
 
40578
 
 
40579
#line 1 "duk_js_call.c"
 
40580
/*
 
40581
 *  Call handling.
 
40582
 *
 
40583
 *  The main work horse functions are:
 
40584
 *    - duk_handle_call(): call to a C/Ecmascript functions
 
40585
 *    - duk_handle_safe_call(): make a protected C call within current activation
 
40586
 *    - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls, including
 
40587
 *      tail calls and coroutine resume
 
40588
 */
 
40589
 
 
40590
/* include removed: duk_internal.h */
 
40591
 
 
40592
/*
 
40593
 *  Arguments object creation.
 
40594
 *
 
40595
 *  Creating arguments objects is a bit finicky, see E5 Section 10.6 for the
 
40596
 *  specific requirements.  Much of the arguments object special behavior is
 
40597
 *  implemented in duk_hobject_props.c, and is enabled by the object flag
 
40598
 *  DUK_HOBJECT_FLAG_SPECIAL_ARGUMENTS.
 
40599
 */
 
40600
 
 
40601
static void duk__create_arguments_object(duk_hthread *thr,
 
40602
                                         duk_hobject *func,
 
40603
                                         duk_hobject *varenv,
 
40604
                                         int idx_argbase,            /* idx of first argument on stack */
 
40605
                                         int num_stack_args) {       /* num args starting from idx_argbase */
 
40606
        duk_context *ctx = (duk_context *) thr;
 
40607
        duk_hobject *arg;          /* 'arguments' */
 
40608
        duk_hobject *formals;      /* formals for 'func' (may be NULL if func is a C function) */
 
40609
        int i_arg;
 
40610
        int i_map;
 
40611
        int i_mappednames;
 
40612
        int i_formals;
 
40613
        int i_argbase;
 
40614
        int n_formals;
 
40615
        int idx;
 
40616
        int need_map;
 
40617
 
 
40618
        DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, idx_argbase=%d, num_stack_args=%d",
 
40619
                     (duk_heaphdr *) func, (duk_heaphdr *) varenv, idx_argbase, num_stack_args);
 
40620
 
 
40621
        DUK_ASSERT(thr != NULL);
 
40622
        DUK_ASSERT(func != NULL);
 
40623
        DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
 
40624
        DUK_ASSERT(varenv != NULL);
 
40625
        DUK_ASSERT(idx_argbase >= 0);  /* assumed to bottom relative */
 
40626
        DUK_ASSERT(num_stack_args >= 0);
 
40627
 
 
40628
        need_map = 0;
 
40629
 
 
40630
        i_argbase = idx_argbase;
 
40631
        DUK_ASSERT(i_argbase >= 0);
 
40632
 
 
40633
        duk_push_hobject(ctx, func);
 
40634
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FORMALS);
 
40635
        formals = duk_get_hobject(ctx, -1);
 
40636
        n_formals = 0;
 
40637
        if (formals) {
 
40638
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
 
40639
                n_formals = duk_require_int(ctx, -1);
 
40640
                duk_pop(ctx);
 
40641
        }
 
40642
        duk_remove(ctx, -2);  /* leave formals on stack for later use */
 
40643
        i_formals = duk_require_top_index(ctx);
 
40644
 
 
40645
        DUK_ASSERT(n_formals >= 0);
 
40646
        DUK_ASSERT(formals != NULL || n_formals == 0);
 
40647
 
 
40648
        DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%d", func, formals, n_formals);
 
40649
 
 
40650
        /* [ ... formals ] */
 
40651
 
 
40652
        /*
 
40653
         *  Create required objects:
 
40654
         *    - 'arguments' object: array-like, but not an array
 
40655
         *    - 'map' object: internal object, tied to 'arguments'
 
40656
         *    - 'mappedNames' object: temporary value used during construction
 
40657
         */
 
40658
 
 
40659
        i_arg = duk_push_object_helper(ctx,
 
40660
                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
 
40661
                                       DUK_HOBJECT_FLAG_ARRAY_PART |
 
40662
                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
 
40663
                                       DUK_BIDX_OBJECT_PROTOTYPE);
 
40664
        DUK_ASSERT(i_arg >= 0);
 
40665
        arg = duk_require_hobject(ctx, -1);
 
40666
        DUK_ASSERT(arg != NULL);
 
40667
 
 
40668
        i_map = duk_push_object_helper(ctx,
 
40669
                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
 
40670
                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
40671
                                       -1);  /* no prototype */
 
40672
        DUK_ASSERT(i_map >= 0);
 
40673
 
 
40674
        i_mappednames = duk_push_object_helper(ctx,
 
40675
                                               DUK_HOBJECT_FLAG_EXTENSIBLE |
 
40676
                                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
 
40677
                                               -1);  /* no prototype */
 
40678
        DUK_ASSERT(i_mappednames >= 0);
 
40679
 
 
40680
        /* [... formals arguments map mappedNames] */
 
40681
 
 
40682
        DUK_DDDPRINT("created arguments related objects: "
 
40683
                     "arguments at index %d -> %!O "
 
40684
                     "map at index %d -> %!O "
 
40685
                     "mappednames at index %d -> %!O",
 
40686
                     i_arg, duk_get_hobject(ctx, i_arg),
 
40687
                     i_map, duk_get_hobject(ctx, i_map),
 
40688
                     i_mappednames, duk_get_hobject(ctx, i_mappednames));
 
40689
 
 
40690
        /*
 
40691
         *  Init arguments properties, map, etc.
 
40692
         */
 
40693
 
 
40694
        duk_push_int(ctx, num_stack_args);
 
40695
        duk_def_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
 
40696
 
 
40697
        /*
 
40698
         *  Init argument related properties
 
40699
         */
 
40700
 
 
40701
        /* step 11 */
 
40702
        idx = num_stack_args - 1;
 
40703
        while (idx >= 0) {
 
40704
                DUK_DDDPRINT("arg idx %d, argbase=%d, argidx=%d", idx, i_argbase, i_argbase + idx);
 
40705
 
 
40706
                DUK_DDDPRINT("define arguments[%d]=arg", idx);
 
40707
                duk_push_int(ctx, idx);
 
40708
                duk_dup(ctx, i_argbase + idx);
 
40709
                duk_def_prop(ctx, i_arg, DUK_PROPDESC_FLAGS_WEC);
 
40710
                DUK_DDDPRINT("defined arguments[%d]=arg", idx);
 
40711
 
 
40712
                /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
 
40713
                if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
 
40714
                        DUK_ASSERT(formals != NULL);
 
40715
 
 
40716
                        DUK_DDDPRINT("strict function, index within formals (%d < %d)", idx, n_formals);
 
40717
 
 
40718
                        duk_get_prop_index(ctx, i_formals, idx);
 
40719
                        DUK_ASSERT(duk_is_string(ctx, -1));
 
40720
 
 
40721
                        duk_dup(ctx, -1);  /* [... name name] */
 
40722
 
 
40723
                        if (!duk_has_prop(ctx, i_mappednames)) {
 
40724
                                /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
 
40725
                                 * differs from the reference model
 
40726
                                 */
 
40727
 
 
40728
                                /* [... name] */
 
40729
 
 
40730
                                need_map = 1;
 
40731
 
 
40732
                                DUK_DDDPRINT("set mappednames[%s]=%d", duk_get_string(ctx, -1), idx);
 
40733
                                duk_dup(ctx, -1);         /* name */
 
40734
                                duk_push_int(ctx, idx);   /* index */
 
40735
                                duk_to_string(ctx, -1);
 
40736
                                duk_def_prop(ctx, i_mappednames, DUK_PROPDESC_FLAGS_WEC);  /* out of spec, must be configurable */
 
40737
 
 
40738
                                DUK_DDDPRINT("set map[%d]=%s", idx, duk_get_string(ctx, -1));
 
40739
                                duk_push_int(ctx, idx);   /* index */
 
40740
                                duk_to_string(ctx, -1);
 
40741
                                duk_dup(ctx, -2);         /* name */
 
40742
                                duk_def_prop(ctx, i_map, DUK_PROPDESC_FLAGS_WEC);  /* out of spec, must be configurable */
 
40743
                        } else {
 
40744
                                /* duk_has_prop() popped the second 'name' */
 
40745
                        }
 
40746
 
 
40747
                        /* [... name] */
 
40748
                        duk_pop(ctx);  /* pop 'name' */
 
40749
                }
 
40750
 
 
40751
                idx--;
 
40752
        }
 
40753
 
 
40754
        DUK_DDDPRINT("actual arguments processed");
 
40755
 
 
40756
        /* step 12 */
 
40757
        if (need_map) {
 
40758
                DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object");
 
40759
 
 
40760
                /* should never happen for a strict callee */
 
40761
                DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
 
40762
 
 
40763
                duk_dup(ctx, i_map);
 
40764
                duk_def_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE);  /* out of spec, don't care */
 
40765
 
 
40766
                /* The variable environment for magic variable bindings needs to be
 
40767
                 * given by the caller and recorded in the arguments object.
 
40768
                 *
 
40769
                 * See E5 Section 10.6, the creation of setters/getters.
 
40770
                 *
 
40771
                 * The variable environment also provides access to the callee, so
 
40772
                 * an explicit (internal) callee property is not needed.
 
40773
                 */
 
40774
 
 
40775
                duk_push_hobject(ctx, varenv);
 
40776
                duk_def_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE);  /* out of spec, don't care */
 
40777
        }
 
40778
 
 
40779
        /* steps 13-14 */
 
40780
        if (DUK_HOBJECT_HAS_STRICT(func)) {
 
40781
                /*
 
40782
                 *  Note: callee/caller are throwers and are not deletable etc.
 
40783
                 *  They could be implemented as virtual properties, but currently
 
40784
                 *  there is no support for virtual properties which are accessors
 
40785
                 *  (only plain virtual properties).  This would not be difficult
 
40786
                 *  to change in duk_hobject_props, but we can make the throwers
 
40787
                 *  normal, concrete properties just as easily.
 
40788
                 *
 
40789
                 *  Note that the specification requires that the *same* thrower
 
40790
                 *  built-in object is used here!  See E5 Section 10.6 main
 
40791
                 *  algoritm, step 14, and Section 13.2.3 which describes the
 
40792
                 *  thrower.  See test case test-arguments-throwers.js.
 
40793
                 */
 
40794
 
 
40795
                DUK_DDDPRINT("strict function, setting caller/callee to throwers");
 
40796
 
 
40797
                duk_def_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
 
40798
                duk_def_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_NONE);
 
40799
        } else {
 
40800
                DUK_DDDPRINT("non-strict function, setting callee to actual value");
 
40801
                duk_push_hobject(ctx, func);
 
40802
                duk_def_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
 
40803
        }
 
40804
 
 
40805
        /* set special behavior only after we're done */
 
40806
        if (need_map) {
 
40807
                /*
 
40808
                 *  Note: special behaviors are only enabled for arguments
 
40809
                 *  objects which have a parameter map (see E5 Section 10.6
 
40810
                 *  main algorithm, step 12).
 
40811
                 *
 
40812
                 *  In particular, a non-strict arguments object with no
 
40813
                 *  mapped formals does *NOT* get special behavior, even
 
40814
                 *  for e.g. "caller" property.  This seems counterintuitive
 
40815
                 *  but seems to be the case.
 
40816
                 */
 
40817
 
 
40818
                /* cannot be strict (never mapped variables) */
 
40819
                DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
 
40820
 
 
40821
                DUK_DDDPRINT("enabling special behavior for arguments object");
 
40822
                DUK_HOBJECT_SET_SPECIAL_ARGUMENTS(arg);
 
40823
        } else {
 
40824
                DUK_DDDPRINT("not enabling special behavior for arguments object");
 
40825
        }
 
40826
 
 
40827
        /* nice log */
 
40828
        DUK_DDDPRINT("final arguments related objects: "
 
40829
                     "arguments at index %d -> %!O "
 
40830
                     "map at index %d -> %!O "
 
40831
                     "mappednames at index %d -> %!O",
 
40832
                     i_arg, duk_get_hobject(ctx, i_arg),
 
40833
                     i_map, duk_get_hobject(ctx, i_map),
 
40834
                     i_mappednames, duk_get_hobject(ctx, i_mappednames));
 
40835
 
 
40836
        /* [args(n) [crud] formals arguments map mappednames] -> [args [crud] arguments] */
 
40837
        duk_pop_2(ctx);
 
40838
        duk_remove(ctx, -2);
 
40839
}
 
40840
 
 
40841
/* Helper for creating the arguments object and adding it to the env record
 
40842
 * on top of the value stack.  This helper has a very strict dependency on
 
40843
 * the shape of the input stack.
 
40844
 */
 
40845
static void duk__handle_createargs_for_call(duk_hthread *thr,
 
40846
                                            duk_hobject *func,
 
40847
                                            duk_hobject *env,
 
40848
                                            int num_stack_args) {
 
40849
        duk_context *ctx = (duk_context *) thr;
 
40850
 
 
40851
        DUK_DDDPRINT("creating arguments object for function call");
 
40852
 
 
40853
        DUK_ASSERT(thr != NULL);
 
40854
        DUK_ASSERT(func != NULL);
 
40855
        DUK_ASSERT(env != NULL);
 
40856
        DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
 
40857
        DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
 
40858
 
 
40859
        /* [... arg1 ... argN envobj] */
 
40860
 
 
40861
        duk__create_arguments_object(thr,
 
40862
                                     func,
 
40863
                                     env,
 
40864
                                     duk_get_top(ctx) - num_stack_args - 1,    /* idx_argbase */
 
40865
                                     num_stack_args);
 
40866
 
 
40867
        /* [... arg1 ... argN envobj argobj] */
 
40868
 
 
40869
        duk_def_prop_stridx(ctx,
 
40870
                            -2,
 
40871
                            DUK_STRIDX_LC_ARGUMENTS,
 
40872
                            DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E :   /* strict: non-deletable, non-writable */
 
40873
                                                           DUK_PROPDESC_FLAGS_WE);  /* non-strict: non-deletable, writable */
 
40874
        /* [... arg1 ... argN envobj] */
 
40875
}
 
40876
 
 
40877
/*
 
40878
 *  Helper for handling a "bound function" chain when a call is being made.
 
40879
 *
 
40880
 *  Follows the bound function chain until a non-bound function is found.
 
40881
 *  Prepends the bound arguments to the value stack (at idx_func + 2),
 
40882
 *  updating 'num_stack_args' in the process.  The 'this' binding is also
 
40883
 *  updated if necessary (at idx_func + 1).  Note that for constructor calls
 
40884
 *  the 'this' binding is never updated by [[BoundThis]].
 
40885
 *
 
40886
 *  FIXME: bound function chains could be collapsed at bound function creation
 
40887
 *  time so that each bound function would point directly to a non-bound
 
40888
 *  function.  This would make call time handling much easier.
 
40889
 */
 
40890
 
 
40891
static void duk__handle_bound_chain_for_call(duk_hthread *thr,
 
40892
                                             int idx_func,
 
40893
                                             int *p_num_stack_args,   /* may be changed by call */
 
40894
                                             duk_hobject **p_func,    /* changed by call */
 
40895
                                             int is_constructor_call) {
 
40896
        duk_context *ctx = (duk_context *) thr;
 
40897
        int num_stack_args;
 
40898
        duk_hobject *func;
 
40899
        duk_uint32_t sanity;
 
40900
 
 
40901
        DUK_ASSERT(thr != NULL);
 
40902
        DUK_ASSERT(p_num_stack_args != NULL);
 
40903
        DUK_ASSERT(p_func != NULL);
 
40904
        DUK_ASSERT(*p_func != NULL);
 
40905
        DUK_ASSERT(DUK_HOBJECT_HAS_BOUND(*p_func));
 
40906
 
 
40907
        num_stack_args = *p_num_stack_args;
 
40908
        func = *p_func;
 
40909
 
 
40910
        sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
 
40911
        do {    
 
40912
                int i, len;
 
40913
 
 
40914
                if (!DUK_HOBJECT_HAS_BOUND(func)) {
 
40915
                        break;
 
40916
                }
 
40917
 
 
40918
                DUK_DDDPRINT("bound function encountered, ptr=%p", (void *) func);
 
40919
 
 
40920
                /* XXX: this could be more compact by accessing the internal properties
 
40921
                 * directly as own properties (they cannot be inherited, and are not
 
40922
                 * externally visible).
 
40923
                 */
 
40924
 
 
40925
                DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%d",
 
40926
                             (void *) func, num_stack_args);
 
40927
 
 
40928
                /* [ ... func this arg1 ... argN ] */
 
40929
 
 
40930
                if (is_constructor_call) {
 
40931
                        /* See: ecmascript-testcases/test-spec-bound-constructor.js */
 
40932
                        DUK_DDDPRINT("constructor call: don't update this binding");
 
40933
                } else {
 
40934
                        duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
 
40935
                        duk_replace(ctx, idx_func + 1);  /* idx_this = idx_func + 1 */
 
40936
                }
 
40937
 
 
40938
                /* [ ... func this arg1 ... argN ] */
 
40939
 
 
40940
                /* XXX: duk_get_length? */
 
40941
                duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS);  /* -> [ ... func this arg1 ... argN _args ] */
 
40942
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);          /* -> [ ... func this arg1 ... argN _args length ] */
 
40943
                len = duk_require_int(ctx, -1);
 
40944
                duk_pop(ctx);
 
40945
                for (i = 0; i < len; i++) {
 
40946
                        /* FIXME: very slow - better to bulk allocate a gap, and copy
 
40947
                         * from args_array directly (we know it has a compact array
 
40948
                         * part, etc).
 
40949
                         */
 
40950
 
 
40951
                        /* [ ... func this <some bound args> arg1 ... argN _args ] */
 
40952
                        duk_get_prop_index(ctx, -1, i);
 
40953
                        duk_insert(ctx, idx_func + 2 + i);  /* idx_args = idx_func + 2 */
 
40954
                }
 
40955
                num_stack_args += len;  /* must be updated to work properly (e.g. creation of 'arguments') */
 
40956
                duk_pop(ctx);
 
40957
 
 
40958
                /* [ ... func this <bound args> arg1 ... argN ] */
 
40959
 
 
40960
                duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
 
40961
                duk_replace(ctx, idx_func);  /* replace also in stack; not strictly necessary */
 
40962
                func = duk_require_hobject(ctx, idx_func);
 
40963
 
 
40964
                DUK_DDDPRINT("bound function handled, num_stack_args=%d, idx_func=%d",
 
40965
                             num_stack_args, idx_func);
 
40966
        } while (--sanity > 0);
 
40967
 
 
40968
        if (sanity == 0) {
 
40969
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "function call bound chain sanity exceeded");
 
40970
        }
 
40971
 
 
40972
        DUK_DDDPRINT("final non-bound function is: %p", (void *) func);
 
40973
 
 
40974
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
40975
        DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) || DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
 
40976
 
 
40977
        /* write back */
 
40978
        *p_num_stack_args = num_stack_args;
 
40979
        *p_func = func;
 
40980
}
 
40981
 
 
40982
/*
 
40983
 *  Helper for setting up var_env and lex_env of an activation,
 
40984
 *  assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
 
40985
 */
 
40986
 
 
40987
static void duk__handle_oldenv_for_call(duk_hthread *thr,
 
40988
                                        duk_hobject *func,
 
40989
                                        duk_activation *act) {
 
40990
        duk_tval *tv;
 
40991
 
 
40992
        DUK_ASSERT(thr != NULL);
 
40993
        DUK_ASSERT(func != NULL);
 
40994
        DUK_ASSERT(act != NULL);
 
40995
        DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
 
40996
        DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
 
40997
 
 
40998
        tv = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
 
40999
        if (tv) {
 
41000
                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
41001
                DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
 
41002
                act->lex_env = DUK_TVAL_GET_OBJECT(tv);
 
41003
 
 
41004
                tv = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_VARENV(thr));
 
41005
                if (tv) {
 
41006
                        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
41007
                        DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
 
41008
                        act->var_env = DUK_TVAL_GET_OBJECT(tv);
 
41009
                } else {
 
41010
                        act->var_env = act->lex_env;
 
41011
                }
 
41012
        } else {
 
41013
                act->lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
41014
                act->var_env = act->lex_env;
 
41015
        }
 
41016
 
 
41017
        DUK_HOBJECT_INCREF(thr, act->lex_env);
 
41018
        DUK_HOBJECT_INCREF(thr, act->var_env);
 
41019
}
 
41020
 
 
41021
/*
 
41022
 *  Helper for updating callee 'caller' property.
 
41023
 */
 
41024
 
 
41025
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
41026
static void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
 
41027
        duk_tval *tv_caller;
 
41028
        duk_hobject *h_tmp;
 
41029
        duk_activation *act_callee;
 
41030
        duk_activation *act_caller;
 
41031
 
 
41032
        DUK_ASSERT(thr != NULL);
 
41033
        DUK_ASSERT(func != NULL);
 
41034
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));  /* bound chain resolved */
 
41035
        DUK_ASSERT(thr->callstack_top >= 1);
 
41036
 
 
41037
        if (DUK_HOBJECT_HAS_STRICT(func)) {
 
41038
                /* Strict functions don't get their 'caller' updated. */
 
41039
                return;
 
41040
        }
 
41041
 
 
41042
        act_callee = thr->callstack + thr->callstack_top - 1;
 
41043
        act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
 
41044
 
 
41045
        /* Backup 'caller' property and update its value. */
 
41046
        tv_caller = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_CALLER(thr));
 
41047
        if (tv_caller) {
 
41048
                /* If caller is global/eval code, 'caller' should be set to
 
41049
                 * 'null'.
 
41050
                 *
 
41051
                 * XXX: there is no special flag to infer this correctly now.
 
41052
                 * The NEWENV flag is used now which works as intended for
 
41053
                 * everything (global code, non-strict eval code, and functions)
 
41054
                 * except strict eval code.  Bound functions are never an issue
 
41055
                 * because 'func' has been resolved to a non-bound function.
 
41056
                 */
 
41057
 
 
41058
                if (act_caller) {
 
41059
                        /* act_caller->func may be NULL in some finalization cases,
 
41060
                         * just treat like we don't know the caller.
 
41061
                         */
 
41062
                        if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
 
41063
                                /* Setting to NULL causes 'caller' to be set to
 
41064
                                 * 'null' as desired.
 
41065
                                 */
 
41066
                                act_caller = NULL;
 
41067
                        }
 
41068
                }
 
41069
 
 
41070
                if (DUK_TVAL_IS_OBJECT(tv_caller)) {
 
41071
                        h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
 
41072
                        DUK_ASSERT(h_tmp != NULL);
 
41073
                        act_callee->prev_caller = h_tmp;
 
41074
 
 
41075
                        /* Previous value doesn't need refcount changes because its ownership
 
41076
                         * is transferred to prev_caller.
 
41077
                         */
 
41078
 
 
41079
                        if (act_caller) {
 
41080
                                DUK_ASSERT(act_caller->func != NULL);
 
41081
                                DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
 
41082
                                DUK_TVAL_INCREF(thr, tv_caller);
 
41083
                        } else {
 
41084
                                DUK_TVAL_SET_NULL(tv_caller);  /* no incref */
 
41085
                        }
 
41086
                } else {
 
41087
                        /* 'caller' must only take on 'null' or function value */
 
41088
                        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
 
41089
                        DUK_ASSERT(act_callee->prev_caller == NULL);
 
41090
                        if (act_caller && act_caller->func) {
 
41091
                                /* Tolerate act_caller->func == NULL which happens in
 
41092
                                 * some finalization cases; treat like unknown caller.
 
41093
                                 */
 
41094
                                DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
 
41095
                                DUK_TVAL_INCREF(thr, tv_caller);
 
41096
                        } else {
 
41097
                                DUK_TVAL_SET_NULL(tv_caller);  /* no incref */
 
41098
                        }
 
41099
                }
 
41100
        }
 
41101
}
 
41102
#endif  /* DUK_USE_FUNC_NONSTD_CALLER_PROPERTY */
 
41103
 
 
41104
/*
 
41105
 *  Determine the effective 'this' binding and coerce the current value
 
41106
 *  on the valstack to the effective one (in-place, at idx_this).
 
41107
 *
 
41108
 *  The current this value in the valstack (at idx_this) represents either:
 
41109
 *    - the caller's requested 'this' binding; or
 
41110
 *    - a 'this' binding accumulated from the bound function chain
 
41111
 *
 
41112
 *  The final 'this' binding for the target function may still be
 
41113
 *  different, and is determined as described in E5 Section 10.4.3.
 
41114
 *
 
41115
 *  For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
 
41116
 *  that the caller has provided the correct 'this' binding explicitly
 
41117
 *  when calling, i.e.:
 
41118
 *
 
41119
 *    - global code: this=global object
 
41120
 *    - direct eval: this=copy from eval() caller's this binding
 
41121
 *    - other eval:  this=global object
 
41122
 *
 
41123
 *  Note: this function may cause a recursive function call with arbitrary
 
41124
 *  side effects, because ToObject() may be called.
 
41125
 */
 
41126
 
 
41127
static void duk__coerce_effective_this_binding(duk_hthread *thr,
 
41128
                                               duk_hobject *func,
 
41129
                                               int idx_this) {
 
41130
        duk_context *ctx = (duk_context *) thr;
 
41131
 
 
41132
        if (DUK_HOBJECT_HAS_STRICT(func)) {
 
41133
                DUK_DDDPRINT("this binding: strict -> use directly");
 
41134
        } else {
 
41135
                duk_tval *tv_this = duk_require_tval(ctx, idx_this);
 
41136
                duk_hobject *obj_global;
 
41137
 
 
41138
                if (DUK_TVAL_IS_OBJECT(tv_this)) {
 
41139
                        DUK_DDDPRINT("this binding: non-strict, object -> use directly");
 
41140
                } else if (DUK_TVAL_IS_UNDEFINED(tv_this) || DUK_TVAL_IS_NULL(tv_this)) {
 
41141
                        DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object");
 
41142
                        obj_global = thr->builtins[DUK_BIDX_GLOBAL];
 
41143
                        if (obj_global) {
 
41144
                                duk_push_hobject(ctx, obj_global);
 
41145
                        } else {
 
41146
                                /*
 
41147
                                 *  This may only happen if built-ins are being "torn down".
 
41148
                                 *  This behavior is out of specification scope.
 
41149
                                 */
 
41150
                                DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead");
 
41151
                                duk_push_undefined(ctx);
 
41152
                        }
 
41153
                        duk_replace(ctx, idx_this);
 
41154
                } else {
 
41155
                        DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)");
 
41156
                        duk_to_object(ctx, idx_this);  /* may have side effects */
 
41157
                }
 
41158
        }
 
41159
}
 
41160
 
 
41161
/*
 
41162
 *  Helper for making various kinds of calls.
 
41163
 *
 
41164
 *  Call flags:
 
41165
 *
 
41166
 *    DUK_CALL_FLAG_PROTECTED        <-->  protected call
 
41167
 *    DUK_CALL_FLAG_IGNORE_RECLIMIT  <-->  ignore C recursion limit,
 
41168
 *                                         for errhandler calls
 
41169
 *    DUK_CALL_FLAG_CONSTRUCTOR_CALL <-->  for 'new Foo()' calls
 
41170
 *
 
41171
 *  Input stack:
 
41172
 *
 
41173
 *    [ func this arg1 ... argN ]
 
41174
 *
 
41175
 *  Output stack:
 
41176
 *
 
41177
 *    [ retval ]         (DUK_EXEC_SUCCESS)
 
41178
 *    [ errobj ]         (DUK_EXEC_ERROR (normal error), protected call)
 
41179
 *
 
41180
 *  Even when executing a protected call an error may be thrown in rare cases.
 
41181
 *  For instance, if we run out of memory when setting up the return stack
 
41182
 *  after a caught error, the out of memory is propagated to the caller.
 
41183
 *  Similarly, API errors (such as invalid input stack shape and invalid
 
41184
 *  indices) cause an error to propagate out of this function.  If there is
 
41185
 *  no catchpoint for this error, the fatal error handler is called.
 
41186
 *
 
41187
 *  See 'execution.txt'.
 
41188
 *
 
41189
 *  The allowed thread states for making a call are:
 
41190
 *    - thr matches heap->curr_thread, and thr is already RUNNING
 
41191
 *    - thr does not match heap->curr_thread (may be NULL or other),
 
41192
 *      and thr is INACTIVE (in this case, a setjmp() catchpoint is
 
41193
 *      always used for thread book-keeping to work properly)
 
41194
 *
 
41195
 *  Like elsewhere, gotos are used to keep indent level minimal and
 
41196
 *  avoiding a dozen helpers with awkward plumbing.
 
41197
 *
 
41198
 *  Note: setjmp() and local variables have a nasty interaction,
 
41199
 *  see execution.txt; non-volatile locals modified after setjmp()
 
41200
 *  call are not guaranteed to keep their value.
 
41201
 */
 
41202
 
 
41203
int duk_handle_call(duk_hthread *thr,
 
41204
                    int num_stack_args,
 
41205
                    int call_flags) {
 
41206
        duk_context *ctx = (duk_context *) thr;
 
41207
        duk_size_t entry_valstack_bottom_index;
 
41208
        duk_size_t entry_callstack_top;
 
41209
        duk_size_t entry_catchstack_top;
 
41210
        int entry_call_recursion_depth;
 
41211
        duk_hthread *entry_curr_thread;
 
41212
        duk_uint8_t entry_thread_state;
 
41213
        volatile int need_setjmp;
 
41214
        duk_jmpbuf * volatile old_jmpbuf_ptr = NULL;    /* ptr is volatile (not the target) */
 
41215
        int idx_func;         /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
 
41216
        int idx_args;         /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
 
41217
        int nargs;            /* # argument registers target function wants (< 0 => "as is") */
 
41218
        int nregs;            /* # total registers target function wants on entry (< 0 => "as is") */
 
41219
        unsigned int vs_min_size;  /* FIXME: type */
 
41220
        duk_hobject *func;    /* 'func' on stack (borrowed reference) */
 
41221
        duk_activation *act;
 
41222
        duk_hobject *env;
 
41223
        duk_jmpbuf our_jmpbuf;
 
41224
        duk_tval tv_tmp;
 
41225
        int retval = DUK_EXEC_ERROR;
 
41226
        int rc;
 
41227
 
 
41228
        DUK_ASSERT(thr != NULL);
 
41229
        DUK_ASSERT(ctx != NULL);
 
41230
        DUK_ASSERT(num_stack_args >= 0);
 
41231
 
 
41232
        /* XXX: currently NULL allocations are not supported; remove if later allowed */
 
41233
        DUK_ASSERT(thr->valstack != NULL);
 
41234
        DUK_ASSERT(thr->callstack != NULL);
 
41235
        DUK_ASSERT(thr->catchstack != NULL);
 
41236
 
 
41237
        /*
 
41238
         *  Preliminaries, required by setjmp() handler.
 
41239
         *
 
41240
         *  Must be careful not to throw an unintended error here.
 
41241
         *
 
41242
         *  Note: careful with indices like '-x'; if 'x' is zero, it
 
41243
         *  refers to valstack_bottom.
 
41244
         */
 
41245
 
 
41246
        entry_valstack_bottom_index = (int) (thr->valstack_bottom - thr->valstack);
 
41247
        entry_callstack_top = thr->callstack_top;
 
41248
        entry_catchstack_top = thr->catchstack_top;
 
41249
        entry_call_recursion_depth = thr->heap->call_recursion_depth;
 
41250
        entry_curr_thread = thr->heap->curr_thread;  /* Note: may be NULL if first call */
 
41251
        entry_thread_state = thr->state;
 
41252
        idx_func = duk_normalize_index(ctx, -num_stack_args - 2);  /* idx_func must be valid, note: non-throwing! */
 
41253
        idx_args = idx_func + 2;                                   /* idx_args is not necessarily valid if num_stack_args == 0 (idx_args then equals top) */
 
41254
 
 
41255
        /* Need a setjmp() catchpoint if a protected call OR if we need to
 
41256
         * do mandatory cleanup.
 
41257
         */
 
41258
        need_setjmp = ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0) || (thr->heap->curr_thread != thr);
 
41259
 
 
41260
        DUK_DDPRINT("duk_handle_call: thr=%p, num_stack_args=%d, "
 
41261
                    "call_flags=%d (protected=%d, ignorerec=%d, constructor=%d), need_setjmp=%d, "
 
41262
                    "valstack_top=%d, idx_func=%d, idx_args=%d, rec_depth=%d/%d, "
 
41263
                    "entry_valstack_bottom_index=%d, entry_callstack_top=%d, entry_catchstack_top=%d, "
 
41264
                    "entry_call_recursion_depth=%d, entry_curr_thread=%p, entry_thread_state=%d",
 
41265
                    (void *) thr,
 
41266
                    num_stack_args,
 
41267
                    call_flags,
 
41268
                    ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0 ? 1 : 0),
 
41269
                    ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
 
41270
                    ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
 
41271
                    need_setjmp,
 
41272
                    duk_get_top(ctx),
 
41273
                    idx_func,
 
41274
                    idx_args,
 
41275
                    thr->heap->call_recursion_depth,
 
41276
                    thr->heap->call_recursion_limit,
 
41277
                    entry_valstack_bottom_index,
 
41278
                    entry_callstack_top,
 
41279
                    entry_catchstack_top,
 
41280
                    entry_call_recursion_depth,
 
41281
                    (void *) entry_curr_thread,
 
41282
                    entry_thread_state);
 
41283
 
 
41284
#ifdef DUK_USE_DDDEBUG
 
41285
        DUK_DPRINT("callstack before call setup:");
 
41286
        DUK_DEBUG_DUMP_CALLSTACK(thr);
 
41287
#endif
 
41288
 
 
41289
        if (idx_func < 0 || idx_args < 0) {
 
41290
                /*
 
41291
                 *  Since stack indices are not reliable, we can't do anything useful
 
41292
                 *  here.  Invoke the existing setjmp catcher, or if it doesn't exist,
 
41293
                 *  call the fatal error handler.
 
41294
                 */
 
41295
 
 
41296
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid arguments");
 
41297
        }
 
41298
 
 
41299
        /*
 
41300
         *  Setup a setjmp() catchpoint first because even the call setup
 
41301
         *  may fail.
 
41302
         */
 
41303
 
 
41304
        if (!need_setjmp) {
 
41305
                DUK_DDDPRINT("don't need a setjmp catchpoint");
 
41306
                goto handle_call;
 
41307
        }
 
41308
 
 
41309
        old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
 
41310
        thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
 
41311
 
 
41312
        if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
 
41313
                DUK_DDDPRINT("setjmp catchpoint setup complete");
 
41314
                goto handle_call;
 
41315
        }
 
41316
 
 
41317
        /*
 
41318
         *  Error during setup, call, or postprocessing of the call.
 
41319
         *  The error value is in heap->lj.value1.
 
41320
         *
 
41321
         *  Note: any local variables accessed here must have their value
 
41322
         *  assigned *before* the setjmp() call, OR they must be declared
 
41323
         *  volatile.  Otherwise their value is not guaranteed to be correct.
 
41324
         *
 
41325
         *  The following are such variables:
 
41326
         *    - duk_handle_call() parameters
 
41327
         *    - entry_*
 
41328
         *    - idx_func
 
41329
         *    - idx_args
 
41330
         *
 
41331
         *  The very first thing we do is restore the previous setjmp catcher.
 
41332
         *  This means that any error in error handling will propagate outwards
 
41333
         *  instead of causing a setjmp() re-entry above.  The *only* actual
 
41334
         *  errors that should happen here are allocation errors.
 
41335
         */
 
41336
 
 
41337
        DUK_DDDPRINT("error caught during protected duk_handle_call(): %!T",
 
41338
                     &thr->heap->lj.value1);
 
41339
 
 
41340
        DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
 
41341
        DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
 
41342
        DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
 
41343
 
 
41344
        /*
 
41345
         *  Restore previous setjmp catchpoint
 
41346
         */
 
41347
 
 
41348
        /* Note: either pointer may be NULL (at entry), so don't assert */
 
41349
        DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p",
 
41350
                     (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
 
41351
                     old_jmpbuf_ptr);
 
41352
 
 
41353
        thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
 
41354
 
 
41355
        if (!(call_flags & DUK_CALL_FLAG_PROTECTED)) {
 
41356
                /*
 
41357
                 *  Caller did not request a protected call but a setjmp
 
41358
                 *  catchpoint was set up to allow cleanup.  So, clean up
 
41359
                 *  and rethrow.
 
41360
                 *
 
41361
                 *  We must restore curr_thread here to ensure that its
 
41362
                 *  current value doesn't end up pointing to a thread object
 
41363
                 *  which has been freed.  This is now a problem because some
 
41364
                 *  call sites (namely duk_safe_call()) *first* unwind stacks
 
41365
                 *  and only then deal with curr_thread.  If those call sites
 
41366
                 *  were fixed, this wouldn't matter here.
 
41367
                 *
 
41368
                 *  Note: this case happens e.g. when heap->curr_thread is
 
41369
                 *  NULL on entry.
 
41370
                 */
 
41371
 
 
41372
                DUK_DDDPRINT("call is not protected -> clean up and rethrow");
 
41373
 
 
41374
                DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
 
41375
                thr->state = entry_thread_state;
 
41376
                DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) ||  /* first call */
 
41377
                           (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) ||  /* other call */
 
41378
                           (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr));     /* current thread */
 
41379
 
 
41380
                /* XXX: should setjmp catcher be responsible for this instead? */
 
41381
                thr->heap->call_recursion_depth = entry_call_recursion_depth;
 
41382
                duk_err_longjmp(thr);
 
41383
                DUK_UNREACHABLE();
 
41384
        }
 
41385
 
 
41386
        duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
 
41387
        duk_hthread_callstack_unwind(thr, entry_callstack_top);
 
41388
        thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
 
41389
 
 
41390
        /* [ ... func this (crud) errobj ] */
 
41391
 
 
41392
        /* FIXME: is there space?  better implementation: write directly over
 
41393
         * 'func' slot to avoid valstack grow issues.
 
41394
         */
 
41395
        duk_push_tval(ctx, &thr->heap->lj.value1);
 
41396
 
 
41397
        /* [ ... func this (crud) errobj ] */
 
41398
 
 
41399
        duk_replace(ctx, idx_func);
 
41400
        duk_set_top(ctx, idx_func + 1);
 
41401
 
 
41402
        /* [ ... errobj ] */
 
41403
 
 
41404
        /* ensure there is internal valstack spare before we exit; this may
 
41405
         * throw an alloc error
 
41406
         */
 
41407
 
 
41408
        duk_require_valstack_resize((duk_context *) thr,
 
41409
                                    (thr->valstack_top - thr->valstack) +            /* top of current func */
 
41410
                                        DUK_VALSTACK_INTERNAL_EXTRA,                 /* + spare => min_new_size */
 
41411
                                    1);                                              /* allow_shrink */
 
41412
 
 
41413
        /* Note: currently a second setjmp restoration is done at the target;
 
41414
         * this is OK, but could be refactored away.
 
41415
         */
 
41416
        retval = DUK_EXEC_ERROR;
 
41417
        goto shrink_and_finished;
 
41418
 
 
41419
 handle_call:
 
41420
        /*
 
41421
         *  Thread state check and book-keeping.
 
41422
         */
 
41423
 
 
41424
        if (thr == thr->heap->curr_thread) {
 
41425
                /* same thread */
 
41426
                if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
 
41427
                        /* should actually never happen, but check anyway */
 
41428
                        goto thread_state_error;
 
41429
                }
 
41430
        } else {
 
41431
                /* different thread */
 
41432
                DUK_ASSERT(thr->heap->curr_thread == NULL ||
 
41433
                           thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
 
41434
                if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
 
41435
                        goto thread_state_error;
 
41436
                }
 
41437
                DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
 
41438
                thr->state = DUK_HTHREAD_STATE_RUNNING;
 
41439
 
 
41440
                /* Note: multiple threads may be simultaneously in the RUNNING
 
41441
                 * state, but not in the same "resume chain".
 
41442
                 */
 
41443
        }
 
41444
 
 
41445
        DUK_ASSERT(thr->heap->curr_thread == thr);
 
41446
        DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
 
41447
 
 
41448
        /*
 
41449
         *  C call recursion depth check, which provides a reasonable upper
 
41450
         *  bound on maximum C stack size (arbitrary C stack growth is only
 
41451
         *  possible by recursive handle_call / handle_safe_call calls).
 
41452
         */
 
41453
 
 
41454
        DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
 
41455
        DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
 
41456
 
 
41457
        if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
 
41458
                DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)");
 
41459
        } else {        
 
41460
                if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
 
41461
                        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "C call stack depth limit");
 
41462
                }
 
41463
                thr->heap->call_recursion_depth++;
 
41464
        }
 
41465
 
 
41466
        /*
 
41467
         *  Check the function type, handle bound function chains,
 
41468
         *  and prepare parameters for the rest of the call handling.
 
41469
         *  Also figure out the effective 'this' binding, which
 
41470
         *  replaces the current value at idx_func + 1.
 
41471
         *
 
41472
         *  If the target function is a 'bound' one, follow the chain
 
41473
         *  of 'bound' functions until a non-bound function is found.
 
41474
         *  During this process, bound arguments are 'prepended' to
 
41475
         *  existing ones, and the "this" binding is overridden.
 
41476
         *  See E5 Section 15.3.4.5.1.
 
41477
         */
 
41478
 
 
41479
        if (!duk_is_callable(thr, idx_func)) {
 
41480
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "call target not callable");
 
41481
        }
 
41482
        func = duk_get_hobject(thr, idx_func);
 
41483
        DUK_ASSERT(func != NULL);
 
41484
 
 
41485
        if (DUK_HOBJECT_HAS_BOUND(func)) {
 
41486
                /* slow path for bound functions */
 
41487
                duk__handle_bound_chain_for_call(thr, idx_func, &num_stack_args, &func, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
 
41488
        }
 
41489
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
41490
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
 
41491
                   DUK_HOBJECT_IS_NATIVEFUNCTION(func));
 
41492
 
 
41493
        duk__coerce_effective_this_binding(thr, func, idx_func + 1);
 
41494
        DUK_DDDPRINT("effective 'this' binding is: %!T", duk_get_tval(ctx, idx_func + 1));
 
41495
 
 
41496
        /* These base values are never used, but if the compiler doesn't know
 
41497
         * that DUK_ERROR() won't return, these are needed to silence warnings.
 
41498
         * On the other hand, scan-build will warn about the values not being
 
41499
         * used, so add a DUK_UNREF.
 
41500
         */
 
41501
        nargs = 0; DUK_UNREF(nargs);
 
41502
        nregs = 0; DUK_UNREF(nregs);
 
41503
 
 
41504
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
41505
                nargs = ((duk_hcompiledfunction *) func)->nargs;
 
41506
                nregs = ((duk_hcompiledfunction *) func)->nregs;
 
41507
                DUK_ASSERT(nregs >= nargs);
 
41508
        } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
 
41509
                /* Note: nargs (and nregs) may be negative for a native,
 
41510
                 * function, which indicates that the function wants the
 
41511
                 * input stack "as is" (i.e. handles "vararg" arguments).
 
41512
                 */
 
41513
                nargs = ((duk_hnativefunction *) func)->nargs;
 
41514
                nregs = nargs;
 
41515
        } else {
 
41516
                /* XXX: this should be an assert */
 
41517
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "call target not a function");
 
41518
        }
 
41519
 
 
41520
        /* [ ... func this arg1 ... argN ] */
 
41521
 
 
41522
        /*
 
41523
         *  Check stack sizes and resize if necessary.
 
41524
         *
 
41525
         *  Call stack is grown by one, catch stack doesn't grow here.
 
41526
         *  Value stack may either grow or shrink, depending on the number
 
41527
         *  of func registers and the number of actual arguments.
 
41528
         */
 
41529
 
 
41530
        duk_hthread_callstack_grow(thr);
 
41531
 
 
41532
        /* if nregs >= 0, func wants args clamped to 'nargs'; else it wants
 
41533
         * all args (= 'num_stack_args')
 
41534
         */
 
41535
 
 
41536
        vs_min_size = (thr->valstack_bottom - thr->valstack) +         /* bottom of current func */
 
41537
                      idx_args;                                        /* bottom of new func */
 
41538
        vs_min_size += (nregs >= 0 ? nregs : num_stack_args);          /* num entries of new func at entry */
 
41539
        if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
 
41540
                vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM;         /* Duktape/C API guaranteed entries (on top of args) */
 
41541
        }
 
41542
        vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA,                    /* + spare */
 
41543
 
 
41544
        duk_require_valstack_resize((duk_context *) thr, vs_min_size, 1 /*allow_shrink*/);
 
41545
 
 
41546
        /*
 
41547
         *  Update idx_retval of current activation.
 
41548
         *
 
41549
         *  Although it might seem this is not necessary (bytecode executor
 
41550
         *  does this for Ecmascript-to-Ecmascript calls; other calls are
 
41551
         *  handled here), this turns out to be necessary for handling yield
 
41552
         *  and resume.  For them, an Ecmascript-to-native call happens, and
 
41553
         *  the Ecmascript call's idx_retval must be set for things to work.
 
41554
         */
 
41555
 
 
41556
        if (thr->callstack_top > 0) {
 
41557
                /* now set unconditionally, regardless of whether current activation
 
41558
                 * is native or not.
 
41559
                 */
 
41560
                (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
 
41561
        }
 
41562
 
 
41563
        /*
 
41564
         *  Setup a preliminary activation.
 
41565
         *
 
41566
         *  Don't touch valstack_bottom or valstack_top yet so that Duktape API
 
41567
         *  calls work normally.
 
41568
         */
 
41569
 
 
41570
        /* [ ... func this arg1 ... argN ] */
 
41571
 
 
41572
        DUK_ASSERT(thr->callstack_top < thr->callstack_size);
 
41573
        act = &thr->callstack[thr->callstack_top];
 
41574
        thr->callstack_top++;
 
41575
        DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
 
41576
        DUK_ASSERT(thr->valstack_top > thr->valstack_bottom);  /* at least effective 'this' */
 
41577
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
41578
 
 
41579
        act->flags = 0;
 
41580
        if (DUK_HOBJECT_HAS_STRICT(func)) {
 
41581
                act->flags |= DUK_ACT_FLAG_STRICT;
 
41582
        }
 
41583
        if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
 
41584
                act->flags |= DUK_ACT_FLAG_CONSTRUCT;
 
41585
                /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
 
41586
        }
 
41587
        if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
 
41588
                /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
 
41589
        }
 
41590
        if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
 
41591
                act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
 
41592
        }
 
41593
 
 
41594
        /* As a first approximation, all calls except Ecmascript-to-Ecmascript
 
41595
         * calls prevent a yield.
 
41596
         */
 
41597
        act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
 
41598
 
 
41599
        act->func = func;
 
41600
        act->var_env = NULL;
 
41601
        act->lex_env = NULL;
 
41602
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
41603
        act->prev_caller = NULL;
 
41604
#endif
 
41605
        act->pc = 0;
 
41606
        act->idx_bottom = entry_valstack_bottom_index + idx_args;
 
41607
#if 0  /* topmost activation idx_retval is considered garbage, no need to init */
 
41608
        act->idx_retval = -1;  /* idx_retval is a 'caller' retval, so init to "unused" here */
 
41609
#endif
 
41610
 
 
41611
        if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
 
41612
                /* duk_hthread_callstack_unwind() will decrease this on unwind */
 
41613
                thr->callstack_preventcount++;
 
41614
        }
 
41615
 
 
41616
        DUK_HOBJECT_INCREF(thr, func);  /* act->func */
 
41617
 
 
41618
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
41619
        duk__update_func_caller_prop(thr, func);
 
41620
        act = thr->callstack + thr->callstack_top - 1;
 
41621
#endif
 
41622
 
 
41623
        /* [... func this arg1 ... argN] */
 
41624
 
 
41625
#ifdef DUK_USE_DDDEBUG
 
41626
        DUK_DPRINT("pushed new activation:");
 
41627
        DUK_DEBUG_DUMP_ACTIVATION(thr, thr->callstack + thr->callstack_top - 1);
 
41628
#endif
 
41629
 
 
41630
        /*
 
41631
         *  Environment record creation and 'arguments' object creation.
 
41632
         *  Named function expression name binding is handled by the
 
41633
         *  compiler; the compiled function's parent env will contain
 
41634
         *  the (immutable) binding already.
 
41635
         *
 
41636
         *  This handling is now identical for C and Ecmascript functions.
 
41637
         *  C functions always have the 'NEWENV' flag set, so their
 
41638
         *  environment record initialization is delayed (which is good).
 
41639
         *
 
41640
         *  Delayed creation (on demand) is handled in duk_js_var.c.
 
41641
         */
 
41642
 
 
41643
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));  /* bound function chain has already been resolved */
 
41644
 
 
41645
        if (!DUK_HOBJECT_HAS_NEWENV(func)) {
 
41646
                /* use existing env (e.g. for non-strict eval); cannot have
 
41647
                 * an own 'arguments' object (but can refer to the existing one)
 
41648
                 */
 
41649
 
 
41650
                DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
 
41651
 
 
41652
                duk__handle_oldenv_for_call(thr, func, act);
 
41653
 
 
41654
                DUK_ASSERT(act->lex_env != NULL);
 
41655
                DUK_ASSERT(act->var_env != NULL);
 
41656
                goto env_done;
 
41657
        }
 
41658
 
 
41659
        DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
 
41660
 
 
41661
        if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
 
41662
                /* no need to create environment record now; leave as NULL */
 
41663
                DUK_ASSERT(act->lex_env == NULL);
 
41664
                DUK_ASSERT(act->var_env == NULL);
 
41665
                goto env_done;
 
41666
        }
 
41667
 
 
41668
        /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
 
41669
        env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
 
41670
        DUK_ASSERT(env != NULL);
 
41671
        
 
41672
        /* [... func this arg1 ... argN envobj] */
 
41673
 
 
41674
        DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
 
41675
        duk__handle_createargs_for_call(thr, func, env, num_stack_args);
 
41676
 
 
41677
        /* [... func this arg1 ... argN envobj] */
 
41678
 
 
41679
        act->lex_env = env;
 
41680
        act->var_env = env;
 
41681
        DUK_HOBJECT_INCREF(thr, env);
 
41682
        DUK_HOBJECT_INCREF(thr, env);  /* XXX: incref by count (2) directly */
 
41683
        duk_pop(ctx);
 
41684
 
 
41685
 env_done:
 
41686
        /* [... func this arg1 ... argN] */
 
41687
 
 
41688
        /*
 
41689
         *  Setup value stack: clamp to 'nargs', fill up to 'nregs'
 
41690
         */
 
41691
 
 
41692
        /* XXX: replace with a single operation */
 
41693
 
 
41694
        if (nregs >= 0) {
 
41695
                duk_set_top(ctx, idx_args + nargs);  /* clamp anything above nargs */
 
41696
                duk_set_top(ctx, idx_args + nregs);  /* extend with undefined */
 
41697
        } else {
 
41698
                /* 'func' wants stack "as is" */
 
41699
        }
 
41700
 
 
41701
#ifdef DUK_USE_DDDEBUG
 
41702
        DUK_DPRINT("callstack after call setup:");
 
41703
        DUK_DEBUG_DUMP_CALLSTACK(thr);
 
41704
#endif
 
41705
 
 
41706
        /*
 
41707
         *  Determine call type; then setup activation and call
 
41708
         */
 
41709
 
 
41710
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
41711
                goto ecmascript_call;
 
41712
        } else {
 
41713
                goto native_call;
 
41714
        }
 
41715
        DUK_UNREACHABLE();
 
41716
 
 
41717
        /*
 
41718
         *  Native (C) call
 
41719
         */
 
41720
 
 
41721
 native_call:
 
41722
        /*
 
41723
         *  Shift to new valstack_bottom.
 
41724
         */
 
41725
 
 
41726
        thr->valstack_bottom = thr->valstack_bottom + idx_args;
 
41727
        /* keep current valstack_top */
 
41728
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
41729
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
41730
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
41731
        DUK_ASSERT(((duk_hnativefunction *) func)->func != NULL);
 
41732
 
 
41733
        /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
 
41734
 
 
41735
        /*
 
41736
         *  Actual function call and return value check.
 
41737
         *
 
41738
         *  Return values:
 
41739
         *    0    success, no return value (default to 'undefined')
 
41740
         *    1    success, one return value on top of stack
 
41741
         *  < 0    error, throw a "magic" error
 
41742
         *  other  invalid
 
41743
         */
 
41744
 
 
41745
        rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
 
41746
 
 
41747
        if (rc < 0) {
 
41748
                duk_error_throw_from_negative_rc(thr, rc);
 
41749
                DUK_UNREACHABLE();
 
41750
        } else if (rc > 1) {
 
41751
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc");
 
41752
        }
 
41753
        DUK_ASSERT(rc == 0 || rc == 1);
 
41754
 
 
41755
        /*
 
41756
         *  Unwind stack(s) and shift back to old valstack_bottom.
 
41757
         */
 
41758
 
 
41759
        DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
 
41760
        DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
 
41761
 
 
41762
#if 0  /* should be no need to unwind */
 
41763
        duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
 
41764
#endif
 
41765
        duk_hthread_callstack_unwind(thr, entry_callstack_top);
 
41766
 
 
41767
        thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
 
41768
        /* keep current valstack_top */
 
41769
 
 
41770
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
41771
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
41772
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
41773
        DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
 
41774
 
 
41775
        /*
 
41776
         *  Manipulate value stack so that return value is on top
 
41777
         *  (pushing an 'undefined' if necessary).
 
41778
         */
 
41779
 
 
41780
        /* XXX: should this happen in the callee's activation or after unwinding? */
 
41781
        if (rc == 0) {
 
41782
                duk_require_stack(ctx, 1);
 
41783
                duk_push_undefined(ctx);
 
41784
        }
 
41785
        /* [... func this (crud) retval] */
 
41786
 
 
41787
        DUK_DDDPRINT("native call retval -> %!T (rc=%d)", duk_get_tval(ctx, -1), rc);
 
41788
 
 
41789
        duk_replace(ctx, idx_func);
 
41790
        duk_set_top(ctx, idx_func + 1);
 
41791
 
 
41792
        /* [... retval] */
 
41793
 
 
41794
        /* ensure there is internal valstack spare before we exit */
 
41795
 
 
41796
        duk_require_valstack_resize((duk_context *) thr,
 
41797
                                    (thr->valstack_top - thr->valstack) +            /* top of current func */
 
41798
                                        DUK_VALSTACK_INTERNAL_EXTRA,                 /* + spare => min_new_size */
 
41799
                                    1);                                              /* allow_shrink */
 
41800
 
 
41801
 
 
41802
        /*
 
41803
         *  Shrink checks and return with success.
 
41804
         */
 
41805
 
 
41806
        retval = DUK_EXEC_SUCCESS;
 
41807
        goto shrink_and_finished;       
 
41808
 
 
41809
        /*
 
41810
         *  Ecmascript call
 
41811
         */
 
41812
 
 
41813
 ecmascript_call:
 
41814
 
 
41815
        /*
 
41816
         *  Shift to new valstack_bottom.
 
41817
         */
 
41818
 
 
41819
        thr->valstack_bottom = thr->valstack_bottom + idx_args;
 
41820
        /* keep current valstack_top */
 
41821
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
41822
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
41823
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
41824
 
 
41825
        /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
 
41826
 
 
41827
        /*
 
41828
         *  Bytecode executor call.
 
41829
         *
 
41830
         *  Execute bytecode, handling any recursive function calls and
 
41831
         *  thread resumptions.  Returns when execution would return from
 
41832
         *  the entry level activation.  When the executor returns, a
 
41833
         *  single return value is left on the stack top.
 
41834
         *
 
41835
         *  The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
 
41836
         *  other types are handled internally by the executor.
 
41837
         *
 
41838
         */
 
41839
 
 
41840
        DUK_DDDPRINT("entering bytecode execution");
 
41841
        duk_js_execute_bytecode(thr);
 
41842
        DUK_DDDPRINT("returned from bytecode execution");
 
41843
 
 
41844
        /*
 
41845
         *  Unwind stack(s) and shift back to old valstack_bottom.
 
41846
         */
 
41847
 
 
41848
        DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
 
41849
 
 
41850
        duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
 
41851
        duk_hthread_callstack_unwind(thr, entry_callstack_top);
 
41852
 
 
41853
        thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
 
41854
        /* keep current valstack_top */
 
41855
 
 
41856
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
41857
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
41858
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
41859
        DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
 
41860
 
 
41861
        /*
 
41862
         *  Manipulate value stack so that return value is on top.
 
41863
         */
 
41864
 
 
41865
        /* [... func this (crud) retval] */
 
41866
 
 
41867
        duk_replace(ctx, idx_func);
 
41868
        duk_set_top(ctx, idx_func + 1);
 
41869
 
 
41870
        /* [... retval] */
 
41871
 
 
41872
        /* ensure there is internal valstack spare before we exit */
 
41873
 
 
41874
        duk_require_valstack_resize((duk_context *) thr,
 
41875
                                    (thr->valstack_top - thr->valstack) +            /* top of current func */
 
41876
                                        DUK_VALSTACK_INTERNAL_EXTRA,                 /* + spare => min_new_size */
 
41877
                                    1);                                              /* allow_shrink */
 
41878
 
 
41879
        /*
 
41880
         *  Shrink checks and return with success.
 
41881
         */
 
41882
 
 
41883
        retval = DUK_EXEC_SUCCESS;
 
41884
        goto shrink_and_finished;       
 
41885
 
 
41886
 shrink_and_finished:
 
41887
        /* these are "soft" shrink checks, whose failures are ignored */
 
41888
        /* XXX: would be nice if fast path was inlined */
 
41889
        duk_hthread_catchstack_shrink_check(thr);
 
41890
        duk_hthread_callstack_shrink_check(thr);
 
41891
        goto finished;
 
41892
 
 
41893
 finished:
 
41894
        if (need_setjmp) {
 
41895
                /* Note: either pointer may be NULL (at entry), so don't assert;
 
41896
                 * this is now done potentially twice, which is OK
 
41897
                 */
 
41898
                DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p (possibly already done)",
 
41899
                             (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
 
41900
                             old_jmpbuf_ptr);
 
41901
                thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
 
41902
 
 
41903
                /* These are just convenience "wiping" of state */
 
41904
                thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
 
41905
                thr->heap->lj.iserror = 0;
 
41906
 
 
41907
                /* FIXME: what about side effects here? finalizer runs should be shielded
 
41908
                 * from errors so even out-of-memory should not be an issue here.
 
41909
                 */
 
41910
                DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
41911
                DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value1);
 
41912
                DUK_TVAL_DECREF(thr, &tv_tmp);
 
41913
 
 
41914
                DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value2);
 
41915
                DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value2);
 
41916
                DUK_TVAL_DECREF(thr, &tv_tmp);
 
41917
 
 
41918
                DUK_DDDPRINT("setjmp catchpoint torn down");
 
41919
        }
 
41920
 
 
41921
        DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
 
41922
        thr->state = entry_thread_state;
 
41923
 
 
41924
        DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) ||  /* first call */
 
41925
                   (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) ||  /* other call */
 
41926
                   (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr));     /* current thread */
 
41927
        
 
41928
        thr->heap->call_recursion_depth = entry_call_recursion_depth;
 
41929
 
 
41930
        return retval;
 
41931
 
 
41932
 thread_state_error:
 
41933
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%d)", thr->state);
 
41934
        DUK_UNREACHABLE();
 
41935
        return DUK_EXEC_ERROR;  /* never executed */
 
41936
}
 
41937
 
 
41938
/*
 
41939
 *  Manipulate value stack so that exactly 'num_stack_rets' return
 
41940
 *  values are at 'idx_retbase' in every case, assuming there are
 
41941
 *  'rc' return values on top of stack.
 
41942
 *
 
41943
 *  This is a bit tricky, because the called C function operates in
 
41944
 *  the same activation record and may have e.g. popped the stack
 
41945
 *  empty (below idx_retbase).
 
41946
 */
 
41947
 
 
41948
static void duk__safe_call_adjust_valstack(duk_hthread *thr, int idx_retbase, int num_stack_rets, int num_actual_rets) {
 
41949
        duk_context *ctx = (duk_context *) thr;
 
41950
        int idx_rcbase;
 
41951
 
 
41952
        DUK_ASSERT(thr != NULL);
 
41953
        DUK_ASSERT(idx_retbase >= 0);
 
41954
        DUK_ASSERT(num_stack_rets >= 0);
 
41955
        DUK_ASSERT(num_actual_rets >= 0);
 
41956
 
 
41957
        idx_rcbase = duk_get_top(ctx) - num_actual_rets;  /* base of known return values */
 
41958
 
 
41959
        DUK_DDDPRINT("adjust valstack after func call: "
 
41960
                     "num_stack_rets=%d, num_actual_rets=%d, stack_top=%d, idx_retbase=%d, idx_rcbase=%d",
 
41961
                     num_stack_rets, num_actual_rets, duk_get_top(ctx), idx_retbase, idx_rcbase);
 
41962
 
 
41963
        DUK_ASSERT(idx_rcbase >= 0);  /* caller must check */
 
41964
 
 
41965
        /* ensure space for final configuration (idx_retbase + num_stack_rets) and
 
41966
         * intermediate configurations
 
41967
         */
 
41968
        duk_require_stack_top(ctx,
 
41969
                              (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
 
41970
                              num_stack_rets);
 
41971
 
 
41972
        /* chop extra retvals away / extend with undefined */
 
41973
        duk_set_top(ctx, idx_rcbase + num_stack_rets);
 
41974
 
 
41975
        if (idx_rcbase >= idx_retbase) {
 
41976
                int count = idx_rcbase - idx_retbase;
 
41977
                int i;
 
41978
 
 
41979
                DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
 
41980
                             "(idx_retbase=%d, idx_rcbase=%d)", idx_retbase, idx_rcbase);
 
41981
 
 
41982
                /* nuke values at idx_retbase to get the first retval (initially
 
41983
                 * at idx_rcbase) to idx_retbase
 
41984
                 */
 
41985
 
 
41986
                DUK_ASSERT(count >= 0);
 
41987
 
 
41988
                for (i = 0; i < count; i++) {
 
41989
                        /* XXX: inefficient; block remove primitive */
 
41990
                        duk_remove(ctx, idx_retbase);
 
41991
                }
 
41992
        } else {
 
41993
                int count = idx_retbase - idx_rcbase;
 
41994
                int i;
 
41995
 
 
41996
                DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
 
41997
                             "(idx_retbase=%d, idx_rcbase=%d)", idx_retbase, idx_rcbase);
 
41998
 
 
41999
                /* insert 'undefined' values at idx_rcbase to get the
 
42000
                 * return values to idx_retbase
 
42001
                 */
 
42002
 
 
42003
                DUK_ASSERT(count > 0);
 
42004
 
 
42005
                for (i = 0; i < count; i++) {
 
42006
                        /* XXX: inefficient; block insert primitive */
 
42007
                        duk_push_undefined(ctx);
 
42008
                        duk_insert(ctx, idx_rcbase);
 
42009
                }
 
42010
        }
 
42011
}
 
42012
 
 
42013
/*
 
42014
 *  Make a "C protected call" within the current activation.
 
42015
 *
 
42016
 *  The allowed thread states for making a call are the same as for
 
42017
 *  duk_handle_call().
 
42018
 *
 
42019
 *  Note that like duk_handle_call(), even if this call is protected,
 
42020
 *  there are a few situations where the current (pre-entry) setjmp
 
42021
 *  catcher (or a fatal error handler if no such catcher exists) is
 
42022
 *  invoked:
 
42023
 *
 
42024
 *    - Blatant API argument errors (e.g. num_stack_args is invalid,
 
42025
 *      so we can't form a reasonable return stack)
 
42026
 *
 
42027
 *    - Errors during error handling, e.g. failure to reallocate
 
42028
 *      space in the value stack due to an alloc error
 
42029
 *
 
42030
 *  Such errors propagate outwards, ultimately to the fatal error
 
42031
 *  handler if nothing else.
 
42032
 */
 
42033
 
 
42034
/* FIXME: bump preventcount by one for the duration of this call? */
 
42035
 
 
42036
int duk_handle_safe_call(duk_hthread *thr,
 
42037
                         duk_safe_call_function func,
 
42038
                         int num_stack_args,
 
42039
                         int num_stack_rets) {
 
42040
        duk_context *ctx = (duk_context *) thr;
 
42041
        duk_size_t entry_valstack_bottom_index;
 
42042
        duk_size_t entry_callstack_top;
 
42043
        duk_size_t entry_catchstack_top;
 
42044
        int entry_call_recursion_depth;
 
42045
        duk_hthread *entry_curr_thread;
 
42046
        duk_uint8_t entry_thread_state;
 
42047
        duk_jmpbuf *old_jmpbuf_ptr = NULL;
 
42048
        duk_jmpbuf our_jmpbuf;
 
42049
        duk_tval tv_tmp;
 
42050
        int idx_retbase;
 
42051
        int retval;
 
42052
        int rc;
 
42053
 
 
42054
        DUK_ASSERT(thr != NULL);
 
42055
        DUK_ASSERT(ctx != NULL);
 
42056
 
 
42057
        /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
 
42058
        entry_valstack_bottom_index = (int) (thr->valstack_bottom - thr->valstack);
 
42059
        entry_callstack_top = thr->callstack_top;
 
42060
        entry_catchstack_top = thr->catchstack_top;
 
42061
        entry_call_recursion_depth = thr->heap->call_recursion_depth;
 
42062
        entry_curr_thread = thr->heap->curr_thread;  /* Note: may be NULL if first call */
 
42063
        entry_thread_state = thr->state;
 
42064
        idx_retbase = duk_get_top(ctx) - num_stack_args;  /* Note: not a valid stack index if num_stack_args == 0 */
 
42065
 
 
42066
        /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
 
42067
        DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%d, num_stack_rets=%d, "
 
42068
                    "valstack_top=%d, idx_retbase=%d, rec_depth=%d/%d, "
 
42069
                    "entry_valstack_bottom_index=%d, entry_callstack_top=%d, entry_catchstack_top=%d, "
 
42070
                    "entry_call_recursion_depth=%d, entry_curr_thread=%p, entry_thread_state=%d",
 
42071
                    (void *) thr, num_stack_args, num_stack_rets,
 
42072
                    duk_get_top(ctx), idx_retbase, thr->heap->call_recursion_depth,
 
42073
                    thr->heap->call_recursion_limit, entry_valstack_bottom_index,
 
42074
                    entry_callstack_top, entry_catchstack_top, entry_call_recursion_depth,
 
42075
                    entry_curr_thread, entry_thread_state);
 
42076
 
 
42077
        if (idx_retbase < 0) {
 
42078
                /*
 
42079
                 *  Since stack indices are not reliable, we can't do anything useful
 
42080
                 *  here.  Invoke the existing setjmp catcher, or if it doesn't exist,
 
42081
                 *  call the fatal error handler.
 
42082
                 */
 
42083
 
 
42084
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid arguments");
 
42085
        }
 
42086
 
 
42087
        /* setjmp catchpoint setup */
 
42088
 
 
42089
        old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
 
42090
        thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
 
42091
 
 
42092
        if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
 
42093
                goto handle_call;
 
42094
        }
 
42095
 
 
42096
        /*
 
42097
         *  Error during call.  The error value is at heap->lj.value1.
 
42098
         *
 
42099
         *  Careful with variable accesses here; must be assigned to before
 
42100
         *  setjmp() or be declared volatile.  See duk_handle_call().
 
42101
         *
 
42102
         *  The following are such variables:
 
42103
         *    - duk_handle_safe_call() parameters
 
42104
         *    - entry_*
 
42105
         *    - idx_retbase
 
42106
         *
 
42107
         *  The very first thing we do is restore the previous setjmp catcher.
 
42108
         *  This means that any error in error handling will propagate outwards
 
42109
         *  instead of causing a setjmp() re-entry above.  The *only* actual
 
42110
         *  errors that should happen here are allocation errors.
 
42111
         */
 
42112
 
 
42113
        DUK_DDDPRINT("error caught during protected duk_handle_safe_call()");
 
42114
 
 
42115
        DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
 
42116
        DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
 
42117
        DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
 
42118
 
 
42119
        /* Note: either pointer may be NULL (at entry), so don't assert;
 
42120
         * these are now restored twice which is OK.
 
42121
         */
 
42122
        thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
 
42123
 
 
42124
        duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
 
42125
        duk_hthread_callstack_unwind(thr, entry_callstack_top);
 
42126
        thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
 
42127
 
 
42128
        /* [ ... | (crud) ] */
 
42129
 
 
42130
        /* FIXME: space in valstack?  see discussion in duk_handle_call. */
 
42131
        duk_push_tval(ctx, &thr->heap->lj.value1);
 
42132
 
 
42133
        /* [ ... | (crud) errobj ] */
 
42134
 
 
42135
        DUK_ASSERT(duk_get_top(ctx) >= 1);  /* at least errobj must be on stack */
 
42136
 
 
42137
        /* check that the valstack has space for the final amount and any
 
42138
         * intermediate space needed; this is unoptimal but should be safe
 
42139
         */
 
42140
        duk_require_stack_top(ctx, idx_retbase + num_stack_rets);  /* final configuration */
 
42141
        duk_require_stack(ctx, num_stack_rets);
 
42142
 
 
42143
        duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1);  /* 1 = num actual 'return values' */
 
42144
 
 
42145
        /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
 
42146
 
 
42147
#ifdef DUK_USE_DDDEBUG
 
42148
        DUK_DDPRINT("protected safe_call error handling finished, thread dump:");
 
42149
        DUK_DEBUG_DUMP_HTHREAD(thr);
 
42150
#endif
 
42151
 
 
42152
        retval = DUK_EXEC_ERROR;
 
42153
        goto shrink_and_finished;
 
42154
 
 
42155
        /*
 
42156
         *  Handle call (inside setjmp)
 
42157
         */
 
42158
 
 
42159
 handle_call:
 
42160
 
 
42161
        DUK_DDDPRINT("safe_call setjmp catchpoint setup complete");
 
42162
 
 
42163
        /*
 
42164
         *  Thread state check and book-keeping.
 
42165
         */
 
42166
 
 
42167
        if (thr == thr->heap->curr_thread) {
 
42168
                /* same thread */
 
42169
                if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
 
42170
                        /* should actually never happen, but check anyway */
 
42171
                        goto thread_state_error;
 
42172
                }
 
42173
        } else {
 
42174
                /* different thread */
 
42175
                DUK_ASSERT(thr->heap->curr_thread == NULL ||
 
42176
                           thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
 
42177
                if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
 
42178
                        goto thread_state_error;
 
42179
                }
 
42180
                DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
 
42181
                thr->state = DUK_HTHREAD_STATE_RUNNING;
 
42182
 
 
42183
                /* Note: multiple threads may be simultaneously in the RUNNING
 
42184
                 * state, but not in the same "resume chain".
 
42185
                 */
 
42186
        }
 
42187
 
 
42188
        DUK_ASSERT(thr->heap->curr_thread == thr);
 
42189
        DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
 
42190
 
 
42191
        /*
 
42192
         *  Recursion limit check.
 
42193
         *
 
42194
         *  Note: there is no need for an "ignore recursion limit" flag
 
42195
         *  for duk_handle_safe_call now.
 
42196
         */
 
42197
 
 
42198
        DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
 
42199
        DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
 
42200
        if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
 
42201
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "C call stack depth limit");
 
42202
        }
 
42203
        thr->heap->call_recursion_depth++;
 
42204
 
 
42205
        /*
 
42206
         *  Valstack spare check
 
42207
         */
 
42208
 
 
42209
        duk_require_stack(ctx, 0);  /* internal spare */
 
42210
 
 
42211
        /*
 
42212
         *  Make the C call
 
42213
         */
 
42214
 
 
42215
        rc = func(ctx);
 
42216
 
 
42217
        DUK_DDDPRINT("safe_call, func rc=%d", rc);
 
42218
 
 
42219
        /*
 
42220
         *  Valstack manipulation for results
 
42221
         */
 
42222
 
 
42223
        /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
 
42224
        DUK_ASSERT(thr->callstack_top == entry_callstack_top);
 
42225
        DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
 
42226
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
42227
        DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
 
42228
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
42229
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
42230
 
 
42231
        if (rc < 0) {
 
42232
                duk_error_throw_from_negative_rc(thr, rc);
 
42233
        }
 
42234
        DUK_ASSERT(rc >= 0);
 
42235
 
 
42236
        if (duk_get_top(ctx) < rc) {
 
42237
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "not enough stack values for safe_call rc");
 
42238
        }
 
42239
 
 
42240
        duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
 
42241
 
 
42242
        /* Note: no need from callstack / catchstack shrink check */
 
42243
        retval = DUK_EXEC_SUCCESS;
 
42244
        goto finished;
 
42245
 
 
42246
 shrink_and_finished:
 
42247
        /* these are "soft" shrink checks, whose failures are ignored */
 
42248
        /* XXX: would be nice if fast path was inlined */
 
42249
        duk_hthread_catchstack_shrink_check(thr);
 
42250
        duk_hthread_callstack_shrink_check(thr);
 
42251
        goto finished;
 
42252
 
 
42253
 finished:
 
42254
        /* Note: either pointer may be NULL (at entry), so don't assert */
 
42255
        thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
 
42256
 
 
42257
        /* These are just convenience "wiping" of state */
 
42258
        thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
 
42259
        thr->heap->lj.iserror = 0;
 
42260
 
 
42261
        /* FIXME: what about side effects here? finalizer runs should be shielded
 
42262
         * from errors so even out-of-memory should not be an issue here.
 
42263
         */
 
42264
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
42265
        DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value1);
 
42266
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
42267
 
 
42268
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value2);
 
42269
        DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value2);
 
42270
        DUK_TVAL_DECREF(thr, &tv_tmp);
 
42271
 
 
42272
        DUK_DDDPRINT("setjmp catchpoint torn down");
 
42273
 
 
42274
        /* FIXME: because we unwind stacks above, thr->heap->curr_thread is at
 
42275
         * risk of pointing to an already freed thread.  This was indeed the
 
42276
         * case in test-bug-multithread-valgrind.c, until duk_handle_call()
 
42277
         * was fixed to restore thr->heap->curr_thread before rethrowing an
 
42278
         * uncaught error.
 
42279
         */
 
42280
        DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
 
42281
        thr->state = entry_thread_state;
 
42282
 
 
42283
        DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) ||  /* first call */
 
42284
                   (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) ||  /* other call */
 
42285
                   (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr));     /* current thread */
 
42286
 
 
42287
        thr->heap->call_recursion_depth = entry_call_recursion_depth;
 
42288
 
 
42289
        /* stack discipline consistency check */
 
42290
        DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
 
42291
 
 
42292
        return retval;
 
42293
 
 
42294
 thread_state_error:
 
42295
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%d)", thr->state);
 
42296
        DUK_UNREACHABLE();
 
42297
        return DUK_EXEC_ERROR;  /* never executed */
 
42298
}
 
42299
 
 
42300
/*
 
42301
 *  Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
 
42302
 *  function (initial) Duktape.Thread.resume().
 
42303
 *
 
42304
 *  Compared to normal calls handled by duk_handle_call(), there are a
 
42305
 *  bunch of differences:
 
42306
 *
 
42307
 *    - the call is never protected
 
42308
 *    - there is no C recursion depth increase (hence an "ignore recursion
 
42309
 *      limit" flag is not applicable)
 
42310
 *    - instead of making the call, this helper just performs the thread
 
42311
 *      setup and returns; the bytecode executor then restarts execution
 
42312
 *      internally
 
42313
 *    - ecmascript functions are never 'vararg' functions (they access
 
42314
 *      varargs through the 'arguments' object)
 
42315
 *
 
42316
 *  The callstack of the target contains an earlier Ecmascript call in case
 
42317
 *  of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
 
42318
 *  is empty in case of an initial Duktape.Thread.resume().
 
42319
 */
 
42320
 
 
42321
void duk_handle_ecma_call_setup(duk_hthread *thr,
 
42322
                                int num_stack_args,
 
42323
                                int call_flags) {
 
42324
        duk_context *ctx = (duk_context *) thr;
 
42325
        int entry_valstack_bottom_index;
 
42326
        int idx_func;         /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
 
42327
        int idx_args;         /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
 
42328
        int nargs;            /* # argument registers target function wants (< 0 => never for ecma calls) */
 
42329
        int nregs;            /* # total registers target function wants on entry (< 0 => never for ecma calls) */
 
42330
        duk_hobject *func;    /* 'func' on stack (borrowed reference) */
 
42331
        duk_activation *act;
 
42332
        duk_hobject *env;
 
42333
        int use_tailcall;
 
42334
 
 
42335
        DUK_ASSERT(thr != NULL);
 
42336
        DUK_ASSERT(ctx != NULL);
 
42337
        DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
 
42338
 
 
42339
        /* XXX: assume these? */
 
42340
        DUK_ASSERT(thr->valstack != NULL);
 
42341
        DUK_ASSERT(thr->callstack != NULL);
 
42342
        DUK_ASSERT(thr->catchstack != NULL);
 
42343
 
 
42344
        /* no need to handle thread state book-keeping here */
 
42345
        DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
 
42346
                   (thr->state == DUK_HTHREAD_STATE_RUNNING &&
 
42347
                    thr->heap->curr_thread == thr));
 
42348
 
 
42349
        /* if a tailcall:
 
42350
         *   - an Ecmascript activation must be on top of the callstack
 
42351
         *   - there cannot be any active catchstack entries
 
42352
         */
 
42353
#ifdef DUK_USE_ASSERTIONS
 
42354
        if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
 
42355
                duk_size_t our_callstack_index;
 
42356
                duk_size_t i;
 
42357
 
 
42358
                DUK_ASSERT(thr->callstack_top >= 1);
 
42359
                our_callstack_index = thr->callstack_top - 1;
 
42360
                DUK_ASSERT_DISABLE(our_callstack_index >= 0);
 
42361
                DUK_ASSERT(our_callstack_index < thr->callstack_size);
 
42362
                DUK_ASSERT(thr->callstack[our_callstack_index].func != NULL);
 
42363
                DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(thr->callstack[our_callstack_index].func));
 
42364
 
 
42365
                /* No entry in the catchstack which would actually catch a
 
42366
                 * throw can refer to the callstack entry being reused.
 
42367
                 * There *can* be catchstack entries referring to the current
 
42368
                 * callstack entry as long as they don't catch (e.g. label sites).
 
42369
                 */
 
42370
 
 
42371
                for (i = 0; i < thr->catchstack_top; i++) {
 
42372
                        DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index ||  /* refer to callstack entries below current */
 
42373
                                   DUK_CAT_GET_TYPE(&thr->catchstack[i]) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
 
42374
                }
 
42375
        }
 
42376
#endif  /* DUK_USE_ASSERTIONS */
 
42377
 
 
42378
        entry_valstack_bottom_index = (int) (thr->valstack_bottom - thr->valstack);
 
42379
        idx_func = duk_normalize_index(thr, -num_stack_args - 2);
 
42380
        idx_args = idx_func + 2;
 
42381
 
 
42382
        DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
 
42383
                    "num_stack_args=%d, call_flags=%d (resume=%d, tailcall=%d), "
 
42384
                    "idx_func=%d, idx_args=%d, entry_valstack_bottom_index=%d",
 
42385
                    (void *) thr,
 
42386
                    num_stack_args,
 
42387
                    call_flags,
 
42388
                    ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
 
42389
                    ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
 
42390
                    idx_func,
 
42391
                    idx_args,
 
42392
                    entry_valstack_bottom_index);
 
42393
 
 
42394
#ifdef DUK_USE_DDDEBUG
 
42395
        DUK_DPRINT("callstack before call setup:");
 
42396
        DUK_DEBUG_DUMP_CALLSTACK(thr);
 
42397
#endif
 
42398
 
 
42399
        if (idx_func < 0 || idx_args < 0) {
 
42400
                /* XXX: assert? compiler is responsible for this never happening */
 
42401
                DUK_ERROR(thr, DUK_ERR_API_ERROR, "invalid func index");
 
42402
        }
 
42403
 
 
42404
        /*
 
42405
         *  Check the function type, handle bound function chains,
 
42406
         *  and prepare parameters for the rest of the call handling.
 
42407
         *  Also figure out the effective 'this' binding, which replaces
 
42408
         *  the current value at idx_func + 1.
 
42409
         *
 
42410
         *  If the target function is a 'bound' one, follow the chain
 
42411
         *  of 'bound' functions until a non-bound function is found.
 
42412
         *  During this process, bound arguments are 'prepended' to
 
42413
         *  existing ones, and the "this" binding is overridden.
 
42414
         *  See E5 Section 15.3.4.5.1.
 
42415
         */
 
42416
 
 
42417
        if (!duk_is_callable(thr, idx_func)) {
 
42418
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "call target not callable");
 
42419
        }
 
42420
        func = duk_get_hobject(thr, idx_func);
 
42421
        DUK_ASSERT(func != NULL);
 
42422
 
 
42423
        if (DUK_HOBJECT_HAS_BOUND(func)) {
 
42424
                /* slow path for bound functions */
 
42425
                duk__handle_bound_chain_for_call(thr, idx_func, &num_stack_args, &func, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
 
42426
        }
 
42427
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
42428
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func));  /* caller must ensure this */
 
42429
 
 
42430
        duk__coerce_effective_this_binding(thr, func, idx_func + 1);
 
42431
        DUK_DDDPRINT("effective 'this' binding is: %!T", duk_get_tval(ctx, idx_func + 1));
 
42432
 
 
42433
        nargs = ((duk_hcompiledfunction *) func)->nargs;
 
42434
        nregs = ((duk_hcompiledfunction *) func)->nregs;
 
42435
        DUK_ASSERT(nregs >= nargs);
 
42436
 
 
42437
        /* [ ... func this arg1 ... argN ] */
 
42438
 
 
42439
        /*
 
42440
         *  Preliminary activation record and valstack manipulation.
 
42441
         *  The concrete actions depend on whether the we're dealing
 
42442
         *  with a tailcall (reuse an existing activation), a resume,
 
42443
         *  or a normal call.
 
42444
         *
 
42445
         *  The basic actions, in varying order, are:
 
42446
         *
 
42447
         *    - Check stack size for call handling
 
42448
         *    - Grow call stack if necessary (non-tail-calls)
 
42449
         *    - Update current activation (idx_retval) if necessary
 
42450
         *      (non-tail, non-resume calls)
 
42451
         *    - Move start of args (idx_args) to valstack bottom
 
42452
         *      (tail calls)
 
42453
         *
 
42454
         *  Don't touch valstack_bottom or valstack_top yet so that Duktape API
 
42455
         *  calls work normally.
 
42456
         */
 
42457
 
 
42458
        /* XXX: some overlapping code; cleanup */
 
42459
        use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
 
42460
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42461
        /* With 'caller' property, tail calls cannot be used without further
 
42462
         * non-trivial fixes, so disable them.
 
42463
         */
 
42464
        DUK_DDDPRINT("tailcall disabled because 'caller' property enabled and target is non-strict");
 
42465
        DUK_ASSERT(use_tailcall == 0);  /* compiler ensures this */
 
42466
#endif
 
42467
 
 
42468
        if (use_tailcall) {
 
42469
                duk_tval *tv1, *tv2;
 
42470
                duk_tval tv_tmp;
 
42471
                duk_size_t cs_index;
 
42472
                int i;
 
42473
 
 
42474
                /*
 
42475
                 *  Tailcall handling
 
42476
                 *
 
42477
                 *  Although the callstack entry is reused, we need to explicitly unwind
 
42478
                 *  the current activation (or simulate an unwind).  In particular, the
 
42479
                 *  current activation must be closed, otherwise something like
 
42480
                 *  test-bug-reduce-judofyr.js results.  Also catchstack needs be unwound
 
42481
                 *  because there may be non-error-catching label entries in valid tailcalls.
 
42482
                 */
 
42483
 
 
42484
                DUK_DDDPRINT("is tailcall, reusing activation at callstack top, at index %d",
 
42485
                             thr->callstack_top - 1);
 
42486
 
 
42487
                act = thr->callstack + thr->callstack_top - 1;
 
42488
                DUK_UNREF(act);  /* unreferenced unless assertions used */
 
42489
 
 
42490
                DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
42491
                DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
 
42492
                DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
 
42493
                DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
 
42494
 
 
42495
                /* Unwind catchstack entries referring to the callstack entry we're reusing */
 
42496
                cs_index = thr->callstack_top - 1;
 
42497
                for (i = thr->catchstack_top - 1; i >= 0; i--) {
 
42498
                        duk_catcher *cat = thr->catchstack + i;
 
42499
                        if (cat->callstack_index != cs_index) {
 
42500
                                /* 'i' is the first entry we'll keep */
 
42501
                                break;
 
42502
                        }
 
42503
                }
 
42504
                duk_hthread_catchstack_unwind(thr, i + 1);
 
42505
 
 
42506
                /* Unwind the topmost callstack entry before reusing it */
 
42507
                DUK_ASSERT(thr->callstack_top > 0);
 
42508
                duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
 
42509
 
 
42510
                /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
 
42511
                thr->callstack_top++;
 
42512
                DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
 
42513
                act = thr->callstack + thr->callstack_top - 1;
 
42514
 
 
42515
                /* Start filling in the activation */
 
42516
                act->func = func;  /* don't want an intermediate exposed state with func == NULL */
 
42517
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42518
                act->prev_caller = NULL;
 
42519
#endif
 
42520
                act->pc = 0;       /* don't want an intermediate exposed state with invalid pc */
 
42521
#ifdef DUK_USE_REFERENCE_COUNTING
 
42522
                DUK_HOBJECT_INCREF(thr, func);
 
42523
                act = thr->callstack + thr->callstack_top - 1;  /* side effects (currently none though) */
 
42524
#endif
 
42525
 
 
42526
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42527
                /* This doesn't actually work properly for tail calls, so tail
 
42528
                 * calls are disabled when DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42529
                 * is in use.
 
42530
                 */
 
42531
                duk__update_func_caller_prop(thr, func);
 
42532
                act = thr->callstack + thr->callstack_top - 1;
 
42533
#endif
 
42534
 
 
42535
                act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
 
42536
                              DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
 
42537
                              DUK_ACT_FLAG_TAILCALLED);
 
42538
 
 
42539
                DUK_ASSERT(act->func == func);      /* already updated */
 
42540
                DUK_ASSERT(act->var_env == NULL);   /* already NULLed (by unwind) */
 
42541
                DUK_ASSERT(act->lex_env == NULL);   /* already NULLed (by unwind) */
 
42542
                DUK_ASSERT(act->pc == 0);           /* already zeroed */
 
42543
                act->idx_bottom = entry_valstack_bottom_index;  /* tail call -> reuse current "frame" */
 
42544
                DUK_ASSERT(nregs >= 0);
 
42545
#if 0  /* topmost activation idx_retval is considered garbage, no need to init */
 
42546
                act->idx_retval = -1;  /* idx_retval is a 'caller' retval, so init to "unused" here */
 
42547
#endif
 
42548
 
 
42549
                /*
 
42550
                 *  Manipulate valstack so that args are on the current bottom and the
 
42551
                 *  previous caller's 'this' binding (which is the value preceding the
 
42552
                 *  current bottom) is replaced with the new 'this' binding:
 
42553
                 *
 
42554
                 *       [ ... this_old | (crud) func this_new arg1 ... argN ]
 
42555
                 *  -->  [ ... this_new | arg1 ... argN ]
 
42556
                 *
 
42557
                 *  For tailcalling to work properly, the valstack bottom must not grow
 
42558
                 *  here; otherwise crud would accumulate on the valstack.
 
42559
                 */
 
42560
 
 
42561
                tv1 = thr->valstack_bottom - 1;
 
42562
                tv2 = thr->valstack_bottom + idx_func + 1;
 
42563
                DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);  /* tv1 is -below- valstack_bottom */
 
42564
                DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
 
42565
                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
42566
                DUK_TVAL_SET_TVAL(tv1, tv2);
 
42567
                DUK_TVAL_INCREF(thr, tv1);
 
42568
                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
42569
                
 
42570
                for (i = 0; i < idx_args; i++) {
 
42571
                        /* XXX: block removal API primitive */
 
42572
                        /* Note: 'func' is popped from valstack here, but it is
 
42573
                         * already reachable from the activation.
 
42574
                         */
 
42575
                        duk_remove(ctx, 0);
 
42576
                }
 
42577
                idx_func = 0; DUK_UNREF(idx_func);  /* really 'not applicable' anymore, should not be referenced after this */
 
42578
                idx_args = 0;
 
42579
 
 
42580
                /* [ ... this_new | arg1 ... argN ] */
 
42581
 
 
42582
                /* now we can also do the valstack resize check */
 
42583
 
 
42584
                duk_require_valstack_resize((duk_context *) thr,
 
42585
                                            (thr->valstack_bottom - thr->valstack) +         /* bottom of current func */
 
42586
                                                idx_args +                                   /* bottom of new func (always 0 here) */
 
42587
                                                nregs +                                      /* num entries of new func at entry */
 
42588
                                                DUK_VALSTACK_INTERNAL_EXTRA,                 /* + spare => min_new_size */
 
42589
                                            1);                                              /* allow_shrink */
 
42590
        } else {
 
42591
                DUK_DDDPRINT("not a tailcall, pushing a new activation to callstack, to index %d",
 
42592
                             thr->callstack_top);
 
42593
 
 
42594
                duk_hthread_callstack_grow(thr);
 
42595
 
 
42596
                /* func wants args clamped to 'nargs' */
 
42597
 
 
42598
                duk_require_valstack_resize((duk_context *) thr,
 
42599
                                            (thr->valstack_bottom - thr->valstack) +         /* bottom of current func */
 
42600
                                                idx_args +                                   /* bottom of new func */
 
42601
                                                nregs +                                      /* num entries of new func at entry */
 
42602
                                                DUK_VALSTACK_INTERNAL_EXTRA,                 /* + spare => min_new_size */
 
42603
                                            1);                                              /* allow_shrink */
 
42604
 
 
42605
                if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
 
42606
                        DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)");
 
42607
                } else {
 
42608
                        DUK_DDDPRINT("update to current activation idx_retval");
 
42609
                        DUK_ASSERT(thr->callstack_top < thr->callstack_size);
 
42610
                        DUK_ASSERT(thr->callstack_top >= 1);
 
42611
                        act = thr->callstack + thr->callstack_top - 1;
 
42612
                        DUK_ASSERT(act->func != NULL);
 
42613
                        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func));
 
42614
                        act->idx_retval = entry_valstack_bottom_index + idx_func;
 
42615
                }
 
42616
 
 
42617
                DUK_ASSERT(thr->callstack_top < thr->callstack_size);
 
42618
                act = &thr->callstack[thr->callstack_top];
 
42619
                thr->callstack_top++;
 
42620
                DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
 
42621
 
 
42622
                DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
42623
                DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
 
42624
                DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
 
42625
 
 
42626
                act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
 
42627
                              DUK_ACT_FLAG_STRICT :
 
42628
                              0);
 
42629
                act->func = func;
 
42630
                act->var_env = NULL;
 
42631
                act->lex_env = NULL;
 
42632
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42633
                act->prev_caller = NULL;
 
42634
#endif
 
42635
                act->pc = 0;
 
42636
                act->idx_bottom = entry_valstack_bottom_index + idx_args;
 
42637
                DUK_ASSERT(nregs >= 0);
 
42638
#if 0  /* topmost activation idx_retval is considered garbage, no need to init */
 
42639
                act->idx_retval = -1;  /* idx_retval is a 'caller' retval, so init to "unused" here */
 
42640
#endif
 
42641
 
 
42642
                DUK_HOBJECT_INCREF(thr, func);  /* act->func */
 
42643
 
 
42644
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
42645
                duk__update_func_caller_prop(thr, func);
 
42646
                act = thr->callstack + thr->callstack_top - 1;
 
42647
#endif
 
42648
        }
 
42649
 
 
42650
        /* [... func this arg1 ... argN]  (not tail call)
 
42651
         * [this | arg1 ... argN]         (tail call)
 
42652
         *
 
42653
         * idx_args updated to match
 
42654
         */
 
42655
 
 
42656
#ifdef DUK_USE_DDDEBUG
 
42657
        DUK_DPRINT("pushed new activation:");
 
42658
        DUK_DEBUG_DUMP_ACTIVATION(thr, thr->callstack + thr->callstack_top - 1);
 
42659
#endif
 
42660
 
 
42661
        /*
 
42662
         *  Environment record creation and 'arguments' object creation.
 
42663
         *  Named function expression name binding is handled by the
 
42664
         *  compiler; the compiled function's parent env will contain
 
42665
         *  the (immutable) binding already.
 
42666
         *
 
42667
         *  Delayed creation (on demand) is handled in duk_js_var.c.
 
42668
         */
 
42669
 
 
42670
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));  /* bound function chain has already been resolved */
 
42671
 
 
42672
        if (!DUK_HOBJECT_HAS_NEWENV(func)) {
 
42673
                /* use existing env (e.g. for non-strict eval); cannot have
 
42674
                 * an own 'arguments' object (but can refer to the existing one)
 
42675
                 */
 
42676
 
 
42677
                duk__handle_oldenv_for_call(thr, func, act);
 
42678
 
 
42679
                DUK_ASSERT(act->lex_env != NULL);
 
42680
                DUK_ASSERT(act->var_env != NULL);
 
42681
                goto env_done;
 
42682
        }
 
42683
 
 
42684
        DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
 
42685
 
 
42686
        if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
 
42687
                /* no need to create environment record now; leave as NULL */
 
42688
                DUK_ASSERT(act->lex_env == NULL);
 
42689
                DUK_ASSERT(act->var_env == NULL);
 
42690
                goto env_done;
 
42691
        }
 
42692
 
 
42693
        /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
 
42694
        env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
 
42695
        DUK_ASSERT(env != NULL);
 
42696
 
 
42697
        /* [... arg1 ... argN envobj] */
 
42698
 
 
42699
        DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
 
42700
        duk__handle_createargs_for_call(thr, func, env, num_stack_args);
 
42701
 
 
42702
        /* [... arg1 ... argN envobj] */
 
42703
 
 
42704
        act->lex_env = env;
 
42705
        act->var_env = env;
 
42706
        DUK_HOBJECT_INCREF(thr, act->lex_env);
 
42707
        DUK_HOBJECT_INCREF(thr, act->var_env);
 
42708
        duk_pop(ctx);
 
42709
 
 
42710
 env_done:
 
42711
        /* [... arg1 ... argN] */
 
42712
 
 
42713
        /*
 
42714
         *  Setup value stack: clamp to 'nargs', fill up to 'nregs'
 
42715
         */
 
42716
 
 
42717
        /* XXX: replace with a single operation */
 
42718
 
 
42719
        DUK_ASSERT(nregs >= 0);
 
42720
        duk_set_top(ctx, idx_args + nargs);  /* clamp anything above nargs */
 
42721
        duk_set_top(ctx, idx_args + nregs);  /* extend with undefined */
 
42722
 
 
42723
#ifdef DUK_USE_DDDEBUG
 
42724
        DUK_DPRINT("callstack after call setup:");
 
42725
        DUK_DEBUG_DUMP_CALLSTACK(thr);
 
42726
#endif
 
42727
 
 
42728
        /*
 
42729
         *  Shift to new valstack_bottom.
 
42730
         */
 
42731
 
 
42732
        thr->valstack_bottom = thr->valstack_bottom + idx_args;
 
42733
        /* keep current valstack_top */
 
42734
        DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
 
42735
        DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
 
42736
        DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
 
42737
 
 
42738
        /*
 
42739
         *  Return to bytecode executor, which will resume execution from
 
42740
         *  the topmost activation.
 
42741
         */
 
42742
}
 
42743
 
 
42744
#line 1 "duk_js_compiler.c"
 
42745
/*
 
42746
 *  Ecmascript compiler.
 
42747
 *
 
42748
 *  Parses an input string and generates a function template result.
 
42749
 *  Compilation may happen in multiple contexts (global code, eval
 
42750
 *  code, function code).
 
42751
 *
 
42752
 *  The parser uses a traditional top-down recursive parsing for the
 
42753
 *  statement level, and an operator precedence based top-down approach
 
42754
 *  for the expression level.  The attempt is to minimize the C stack
 
42755
 *  depth.  Bytecode is generated directly without an intermediate
 
42756
 *  representation (tree), at the cost of needing two passes over each
 
42757
 *  function.
 
42758
 *
 
42759
 *  The top-down recursive parser functions are named "duk__parse_XXX".
 
42760
 *
 
42761
 *  Recursion limits are in key functions to prevent arbitrary C recursion:
 
42762
 *  function body parsing, statement parsing, and expression parsing.
 
42763
 *
 
42764
 *  See doc/compiler.txt for discussion on the design.
 
42765
 */
 
42766
 
 
42767
/* include removed: duk_internal.h */
 
42768
 
 
42769
/* if highest bit of a register number is set, it refers to a constant instead */
 
42770
#define DUK__CONST_MARKER                 DUK_JS_CONST_MARKER
 
42771
 
 
42772
/* for array and object literals */
 
42773
#define DUK__MAX_ARRAY_INIT_VALUES        20
 
42774
#define DUK__MAX_OBJECT_INIT_PAIRS        10
 
42775
 
 
42776
/* FIXME: hack, remove when const lookup is not O(n) */
 
42777
#define DUK__GETCONST_MAX_CONSTS_CHECK    256
 
42778
 
 
42779
/* these limits are based on bytecode limits */
 
42780
#define DUK__MAX_CONSTS                   (DUK_BC_BC_MAX + 1)
 
42781
#define DUK__MAX_FUNCS                    (DUK_BC_BC_MAX + 1)
 
42782
#define DUK__MAX_TEMPS                    (DUK_BC_BC_MAX + 1)
 
42783
 
 
42784
#define DUK__RECURSION_INCREASE(comp_ctx,thr)  do { \
 
42785
                DUK_DDDPRINT("RECURSION INCREASE: %s:%d", DUK_FILE_MACRO, DUK_LINE_MACRO); \
 
42786
                duk__recursion_increase((comp_ctx)); \
 
42787
        } while (0)
 
42788
 
 
42789
#define DUK__RECURSION_DECREASE(comp_ctx,thr)  do { \
 
42790
                DUK_DDDPRINT("RECURSION DECREASE: %s:%d", DUK_FILE_MACRO, DUK_LINE_MACRO); \
 
42791
                duk__recursion_decrease((comp_ctx)); \
 
42792
        } while (0)
 
42793
 
 
42794
/* Note: slots limits below are quite approximate right now, and because they
 
42795
 * overlap (in control flow), some can be eliminated.
 
42796
 */
 
42797
 
 
42798
#define DUK__COMPILE_ENTRY_SLOTS          8
 
42799
#define DUK__FUNCTION_INIT_REQUIRE_SLOTS  16
 
42800
#define DUK__FUNCTION_BODY_REQUIRE_SLOTS  16
 
42801
#define DUK__PARSE_STATEMENTS_SLOTS       16
 
42802
#define DUK__PARSE_EXPR_SLOTS             16
 
42803
 
 
42804
/* Temporary structure used to pass a stack allocated region through
 
42805
 * duk_safe_call().
 
42806
 */
 
42807
typedef struct {
 
42808
        int flags;
 
42809
        duk_compiler_ctx comp_ctx_alloc;
 
42810
        duk_lexer_point lex_pt_alloc;
 
42811
} duk__compiler_stkstate;
 
42812
 
 
42813
/*
 
42814
 *  Prototypes
 
42815
 */
 
42816
 
 
42817
/* lexing */
 
42818
static void duk__advance_helper(duk_compiler_ctx *comp_ctx, int expect);
 
42819
static void duk__advance_expect(duk_compiler_ctx *comp_ctx, int expect);
 
42820
static void duk__advance(duk_compiler_ctx *ctx);
 
42821
 
 
42822
/* function helpers */
 
42823
static void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
 
42824
static void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
 
42825
static void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, int *out_stmt_value_reg);
 
42826
static void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
 
42827
static int duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
 
42828
 
 
42829
/* code emission */
 
42830
static int duk__get_current_pc(duk_compiler_ctx *comp_ctx);
 
42831
static duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, int pc);
 
42832
static void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr ins);
 
42833
#if 0  /* unused */
 
42834
static void duk__emit_op_only(duk_compiler_ctx *comp_ctx, int op);
 
42835
#endif
 
42836
static void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, int op_flags, int a, int b, int c);
 
42837
static void duk__emit_a_b(duk_compiler_ctx *comp_ctx, int op_flags, int a, int b);
 
42838
#if 0  /* unused */
 
42839
static void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a);
 
42840
#endif
 
42841
static void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, int op_flags, int a, int bc);
 
42842
static void duk__emit_abc(duk_compiler_ctx *comp_ctx, int op, int abc);
 
42843
static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop_flags, int b, int c);
 
42844
static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop_flags, int b);
 
42845
static void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, int extraop, int bc);
 
42846
static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop_flags);
 
42847
static void duk__emit_loadint(duk_compiler_ctx *comp_ctx, int reg, int val);
 
42848
static void duk__emit_jump(duk_compiler_ctx *comp_ctx, int target_pc);
 
42849
static int duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
 
42850
static void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, int jump_pc);
 
42851
static void duk__patch_jump(duk_compiler_ctx *comp_ctx, int jump_pc, int target_pc);
 
42852
static void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, int jump_pc);
 
42853
static void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, int trycatch_pc, int reg_catch, int const_varname, int flags);
 
42854
static void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, int regconst);
 
42855
static void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, int regconst);
 
42856
static void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
 
42857
 
 
42858
/* FIXME */
 
42859
static void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
 
42860
static void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
 
42861
static int duk__is_whole_get_i32(double x, duk_int32_t *ival);
 
42862
 
 
42863
/* ivalue/ispec helpers */
 
42864
static int duk__alloctemps(duk_compiler_ctx *comp_ctx, int num);
 
42865
static int duk__alloctemp(duk_compiler_ctx *comp_ctx);
 
42866
static void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, int temp_next);
 
42867
static int duk__getconst(duk_compiler_ctx *comp_ctx);
 
42868
static int duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
 
42869
                                     duk_ispec *x,
 
42870
                                     int forced_reg,
 
42871
                                     int flags);
 
42872
static int duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, int forced_reg);
 
42873
static void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg);
 
42874
static void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
 
42875
static void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
 
42876
static int duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
 
42877
                                      duk_ivalue *x,
 
42878
                                      int forced_reg,
 
42879
                                      int flags);
 
42880
static int duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
 
42881
#if 0  /* unused */
 
42882
static int duk__ivalue_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
 
42883
#endif
 
42884
static int duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg);
 
42885
static int duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
 
42886
 
 
42887
/* identifier handling */
 
42888
static int duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
 
42889
static int duk__lookup_lhs(duk_compiler_ctx *ctx, int *out_reg_varbind, int *out_reg_varname);
 
42890
 
 
42891
/* label handling */
 
42892
static void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, int pc_label, int label_id);
 
42893
static void duk__update_label_flags(duk_compiler_ctx *comp_ctx, int label_id, int flags);
 
42894
static void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, int is_break, int *out_label_id, int *out_label_catch_depth, int *out_label_pc, int *out_is_closest);
 
42895
static void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, int len);
 
42896
 
 
42897
/* top-down expression parser */
 
42898
static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42899
static void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
 
42900
static int duk__expr_lbp(duk_compiler_ctx *comp_ctx);
 
42901
static int duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
 
42902
 
 
42903
/* exprtop is the top level variant which resets nud/led counts */
 
42904
static void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42905
static void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, int rbp_flags);
 
42906
 
 
42907
/* convenience helpers */
 
42908
static int duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42909
#if 0  /* unused */
 
42910
static int duk__expr_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp);
 
42911
#endif
 
42912
static int duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags, int forced_reg);
 
42913
static int duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42914
static void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42915
static void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42916
static int duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42917
#if 0  /* unused */
 
42918
static int duk__exprtop_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42919
static int duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags, int forced_reg);
 
42920
#endif
 
42921
static int duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42922
#if 0  /* unused */
 
42923
static void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags);
 
42924
#endif
 
42925
 
 
42926
/* expression parsing helpers */
 
42927
static int duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42928
static void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42929
static void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42930
static int duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, int new_key_flags);
 
42931
 
 
42932
/* statement parsing */
 
42933
static void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int expr_flags, int *out_reg_varname, int *out_reg_varbind);
 
42934
static void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42935
static void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site);
 
42936
static void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site);
 
42937
static void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42938
static void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site);
 
42939
static void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site);
 
42940
static void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42941
static void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42942
static void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42943
static void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42944
static void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
 
42945
static void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int allow_source_elem);
 
42946
static void duk__parse_stmts(duk_compiler_ctx *comp_ctx, int allow_source_elem, int expect_eof);
 
42947
 
 
42948
static void duk__parse_func_body(duk_compiler_ctx *comp_ctx, int expect_eof, int implicit_return_value);
 
42949
static void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
 
42950
static void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, int is_decl, int is_setget);
 
42951
static int duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, int is_decl, int is_setget);
 
42952
 
 
42953
/*
 
42954
 *  Parser control values for tokens.  The token table is ordered by the
 
42955
 *  DUK_TOK_XXX defines.
 
42956
 *
 
42957
 *  The binding powers are for lbp() use (i.e. for use in led() context).
 
42958
 *  Binding powers are positive for typing convenience, and bits at the
 
42959
 *  top should be reserved for flags.  Binding power step must be higher
 
42960
 *  than 1 so that binding power "lbp - 1" can be used for right associative
 
42961
 *  operators.  Currently a step of 2 is used (which frees one more bit for
 
42962
 *  flags).
 
42963
 */
 
42964
 
 
42965
/* FIXME: actually single step levels would work just fine, clean up */
 
42966
 
 
42967
/* binding power "levels" (see doc/compiler.txt) */
 
42968
#define DUK__BP_INVALID                0             /* always terminates led() */
 
42969
#define DUK__BP_EOF                    2
 
42970
#define DUK__BP_CLOSING                4             /* token closes expression, e.g. ')', ']' */
 
42971
#define DUK__BP_FOR_EXPR               DUK__BP_CLOSING    /* bp to use when parsing a top level Expression */
 
42972
#define DUK__BP_COMMA                  6
 
42973
#define DUK__BP_ASSIGNMENT             8
 
42974
#define DUK__BP_CONDITIONAL            10
 
42975
#define DUK__BP_LOR                    12
 
42976
#define DUK__BP_LAND                   14
 
42977
#define DUK__BP_BOR                    16
 
42978
#define DUK__BP_BXOR                   18
 
42979
#define DUK__BP_BAND                   20
 
42980
#define DUK__BP_EQUALITY               22
 
42981
#define DUK__BP_RELATIONAL             24
 
42982
#define DUK__BP_SHIFT                  26
 
42983
#define DUK__BP_ADDITIVE               28
 
42984
#define DUK__BP_MULTIPLICATIVE         30
 
42985
#define DUK__BP_POSTFIX                32
 
42986
#define DUK__BP_CALL                   34
 
42987
#define DUK__BP_MEMBER                 36
 
42988
 
 
42989
#define DUK__TOKEN_LBP_BP_MASK         0x1f
 
42990
#define DUK__TOKEN_LBP_FLAG_NO_REGEXP  (1 << 5)   /* regexp literal must not follow this token */
 
42991
#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6)   /* FIXME: terminates expression; e.g. post-increment/-decrement */
 
42992
#define DUK__TOKEN_LBP_FLAG_UNUSED     (1 << 7)   /* spare */
 
42993
 
 
42994
#define DUK__TOKEN_LBP_GET_BP(x)       ((int) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
 
42995
 
 
42996
#define DUK__MK_LBP(bp)                ((bp) >> 1)    /* bp is assumed to be even */
 
42997
#define DUK__MK_LBP_FLAGS(bp,flags)    (((bp) >> 1) | (flags))
 
42998
 
 
42999
static const duk_int8_t duk__token_lbp[] = {
 
43000
        DUK__MK_LBP(DUK__BP_EOF),                                 /* DUK_TOK_EOF */
 
43001
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LINETERM */
 
43002
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_COMMENT */
 
43003
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_IDENTIFIER */
 
43004
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_BREAK */
 
43005
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CASE */
 
43006
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CATCH */
 
43007
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CONTINUE */
 
43008
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DEBUGGER */
 
43009
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DEFAULT */
 
43010
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DELETE */
 
43011
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DO */
 
43012
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_ELSE */
 
43013
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FINALLY */
 
43014
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FOR */
 
43015
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FUNCTION */
 
43016
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IF */
 
43017
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_IN */
 
43018
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_INSTANCEOF */
 
43019
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_NEW */
 
43020
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_RETURN */
 
43021
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SWITCH */
 
43022
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_THIS */
 
43023
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_THROW */
 
43024
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_TRY */
 
43025
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_TYPEOF */
 
43026
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_VAR */
 
43027
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_VOID */
 
43028
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_WHILE */
 
43029
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_WITH */
 
43030
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CLASS */
 
43031
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CONST */
 
43032
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_ENUM */
 
43033
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_EXPORT */
 
43034
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_EXTENDS */
 
43035
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IMPORT */
 
43036
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SUPER */
 
43037
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_NULL */
 
43038
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_TRUE */
 
43039
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_FALSE */
 
43040
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_GET */
 
43041
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SET */
 
43042
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IMPLEMENTS */
 
43043
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_INTERFACE */
 
43044
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LET */
 
43045
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PACKAGE */
 
43046
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PRIVATE */
 
43047
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PROTECTED */
 
43048
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PUBLIC */
 
43049
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_STATIC */
 
43050
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_YIELD */
 
43051
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LCURLY */
 
43052
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RCURLY */
 
43053
        DUK__MK_LBP(DUK__BP_MEMBER),                              /* DUK_TOK_LBRACKET */
 
43054
        DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RBRACKET */
 
43055
        DUK__MK_LBP(DUK__BP_CALL),                                /* DUK_TOK_LPAREN */
 
43056
        DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RPAREN */
 
43057
        DUK__MK_LBP(DUK__BP_MEMBER),                              /* DUK_TOK_PERIOD */
 
43058
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SEMICOLON */
 
43059
        DUK__MK_LBP(DUK__BP_COMMA),                               /* DUK_TOK_COMMA */
 
43060
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_LT */
 
43061
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_GT */
 
43062
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_LE */
 
43063
        DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_GE */
 
43064
        DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_EQ */
 
43065
        DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_NEQ */
 
43066
        DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_SEQ */
 
43067
        DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_SNEQ */
 
43068
        DUK__MK_LBP(DUK__BP_ADDITIVE),                            /* DUK_TOK_ADD */
 
43069
        DUK__MK_LBP(DUK__BP_ADDITIVE),                            /* DUK_TOK_SUB */
 
43070
        DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_MUL */
 
43071
        DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_DIV */
 
43072
        DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_MOD */
 
43073
        DUK__MK_LBP(DUK__BP_POSTFIX),                             /* DUK_TOK_INCREMENT */
 
43074
        DUK__MK_LBP(DUK__BP_POSTFIX),                             /* DUK_TOK_DECREMENT */
 
43075
        DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_ALSHIFT */
 
43076
        DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_ARSHIFT */
 
43077
        DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_RSHIFT */
 
43078
        DUK__MK_LBP(DUK__BP_BAND),                                /* DUK_TOK_BAND */
 
43079
        DUK__MK_LBP(DUK__BP_BOR),                                 /* DUK_TOK_BOR */
 
43080
        DUK__MK_LBP(DUK__BP_BXOR),                                /* DUK_TOK_BXOR */
 
43081
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LNOT */
 
43082
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_BNOT */
 
43083
        DUK__MK_LBP(DUK__BP_LAND),                                /* DUK_TOK_LAND */
 
43084
        DUK__MK_LBP(DUK__BP_LOR),                                 /* DUK_TOK_LOR */
 
43085
        DUK__MK_LBP(DUK__BP_CONDITIONAL),                         /* DUK_TOK_QUESTION */
 
43086
        DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_COLON */
 
43087
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_EQUALSIGN */
 
43088
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ADD_EQ */
 
43089
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_SUB_EQ */
 
43090
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_MUL_EQ */
 
43091
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_DIV_EQ */
 
43092
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_MOD_EQ */
 
43093
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ALSHIFT_EQ */
 
43094
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ARSHIFT_EQ */
 
43095
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_RSHIFT_EQ */
 
43096
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BAND_EQ */
 
43097
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BOR_EQ */
 
43098
        DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BXOR_EQ */
 
43099
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_NUMBER */
 
43100
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_STRING */
 
43101
        DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_REGEXP */
 
43102
};
 
43103
 
 
43104
/*
 
43105
 *  Misc helpers
 
43106
 */
 
43107
 
 
43108
static void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
 
43109
        DUK_ASSERT(comp_ctx != NULL);
 
43110
        DUK_ASSERT(comp_ctx->recursion_depth >= 0);
 
43111
        if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
 
43112
                DUK_ERROR(comp_ctx->thr, DUK_ERR_RANGE_ERROR, "compiler recursion limit");
 
43113
        }
 
43114
        comp_ctx->recursion_depth++;
 
43115
}
 
43116
 
 
43117
static void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
 
43118
        DUK_ASSERT(comp_ctx != NULL);
 
43119
        DUK_ASSERT(comp_ctx->recursion_depth > 0);
 
43120
        comp_ctx->recursion_depth--;
 
43121
}
 
43122
 
 
43123
static int duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
 
43124
        DUK_UNREF(comp_ctx);
 
43125
        DUK_ASSERT(h != NULL);
 
43126
        return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
 
43127
}
 
43128
 
 
43129
static int duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
 
43130
        DUK_ASSERT(h != NULL);
 
43131
        return (comp_ctx->curr_func.is_strict &&
 
43132
                DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
 
43133
}
 
43134
 
 
43135
/*
 
43136
 *  Parser duk__advance() token eating functions
 
43137
 */
 
43138
 
 
43139
/* FIXME: valstack handling is awkward.  Add a valstack helper which
 
43140
 * avoids dup():ing; valstack_copy(src, dst)?
 
43141
 */
 
43142
 
 
43143
static void duk__advance_helper(duk_compiler_ctx *comp_ctx, int expect) {
 
43144
        duk_hthread *thr = comp_ctx->thr;
 
43145
        duk_context *ctx = (duk_context *) thr;
 
43146
        int regexp;
 
43147
 
 
43148
        DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL);  /* MAXVAL is inclusive */
 
43149
 
 
43150
        /*
 
43151
         *  Use current token to decide whether a RegExp can follow.
 
43152
         *
 
43153
         *  We can use either 't' or 't_nores'; the latter would not
 
43154
         *  recognize keywords.  Some keywords can be followed by a
 
43155
         *  RegExp (e.g. "return"), so using 't' is better.  This is
 
43156
         *  not trivial, see doc/compiler.txt.
 
43157
         */
 
43158
 
 
43159
        regexp = 1;
 
43160
        if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
 
43161
                regexp = 0;
 
43162
        }
 
43163
        if (comp_ctx->curr_func.reject_regexp_in_adv) {
 
43164
                comp_ctx->curr_func.reject_regexp_in_adv = 0;
 
43165
                regexp = 0;
 
43166
        }
 
43167
 
 
43168
        if (expect >= 0 && comp_ctx->curr_token.t != expect) {
 
43169
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "parse error (expected token %d, got %d)",
 
43170
                          expect, comp_ctx->curr_token.t);
 
43171
        }
 
43172
 
 
43173
        /* make current token the previous; need to fiddle with valstack "backing store" */
 
43174
        DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
 
43175
        duk_dup(ctx, comp_ctx->tok11_idx);
 
43176
        duk_replace(ctx, comp_ctx->tok21_idx);
 
43177
        duk_dup(ctx, comp_ctx->tok12_idx);
 
43178
        duk_replace(ctx, comp_ctx->tok22_idx);
 
43179
 
 
43180
        /* parse new token */
 
43181
        duk_lexer_parse_js_input_element(&comp_ctx->lex,
 
43182
                                         &comp_ctx->curr_token,
 
43183
                                         comp_ctx->curr_func.is_strict,
 
43184
                                         regexp);
 
43185
 
 
43186
        DUK_DDDPRINT("advance: curr: tok=%d/%d,%d-%d,term=%d,%!T,%!T "
 
43187
                     "prev: tok=%d/%d,%d-%d,term=%d,%!T,%!T",
 
43188
                     comp_ctx->curr_token.t,
 
43189
                     comp_ctx->curr_token.t_nores,
 
43190
                     comp_ctx->curr_token.start_line,
 
43191
                     comp_ctx->curr_token.end_line,
 
43192
                     comp_ctx->curr_token.lineterm,
 
43193
                     duk_get_tval(ctx, comp_ctx->tok11_idx),
 
43194
                     duk_get_tval(ctx, comp_ctx->tok12_idx),
 
43195
                     comp_ctx->prev_token.t,
 
43196
                     comp_ctx->prev_token.t_nores,
 
43197
                     comp_ctx->prev_token.start_line,
 
43198
                     comp_ctx->prev_token.end_line,
 
43199
                     comp_ctx->prev_token.lineterm,
 
43200
                     duk_get_tval(ctx, comp_ctx->tok21_idx),
 
43201
                     duk_get_tval(ctx, comp_ctx->tok22_idx));
 
43202
}
 
43203
 
 
43204
/* advance, expecting current token to be a specific token; parse next token in regexp context */
 
43205
static void duk__advance_expect(duk_compiler_ctx *comp_ctx, int expect) {
 
43206
        duk__advance_helper(comp_ctx, expect);
 
43207
}
 
43208
 
 
43209
/* advance, whatever the current token is; parse next token in regexp context */
 
43210
static void duk__advance(duk_compiler_ctx *comp_ctx) {
 
43211
        duk__advance_helper(comp_ctx, -1);
 
43212
}
 
43213
 
 
43214
/*
 
43215
 *  Helpers for duk_compiler_func.
 
43216
 */
 
43217
 
 
43218
/* init function state: inits valstack allocations */
 
43219
static void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
 
43220
        duk_compiler_func *func = &comp_ctx->curr_func;
 
43221
        duk_hthread *thr = comp_ctx->thr;
 
43222
        duk_context *ctx = (duk_context *) thr;
 
43223
        int entry_top;
 
43224
 
 
43225
        entry_top = duk_get_top(ctx);
 
43226
 
 
43227
        DUK_MEMZERO(func, sizeof(*func));  /* intentional overlap with earlier memzero */
 
43228
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
43229
        func->h_name = NULL;
 
43230
        func->h_code = NULL;
 
43231
        func->h_consts = NULL;
 
43232
        func->h_funcs = NULL;
 
43233
        func->h_decls = NULL;
 
43234
        func->h_labelnames = NULL;
 
43235
        func->h_labelinfos = NULL;
 
43236
        func->h_argnames = NULL;
 
43237
        func->h_varmap = NULL;
 
43238
#endif
 
43239
 
 
43240
        duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
 
43241
 
 
43242
        /* FIXME: getter for dynamic buffer */
 
43243
 
 
43244
        duk_push_dynamic_buffer(ctx, 0);
 
43245
        func->code_idx = entry_top + 0;
 
43246
        func->h_code = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
 
43247
        DUK_ASSERT(func->h_code != NULL);
 
43248
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_code));
 
43249
 
 
43250
        duk_push_array(ctx);
 
43251
        func->consts_idx = entry_top + 1;
 
43252
        func->h_consts = duk_get_hobject(ctx, entry_top + 1);
 
43253
        DUK_ASSERT(func->h_consts != NULL);
 
43254
 
 
43255
        duk_push_array(ctx);
 
43256
        func->funcs_idx = entry_top + 2;
 
43257
        func->h_funcs = duk_get_hobject(ctx, entry_top + 2);
 
43258
        DUK_ASSERT(func->h_funcs != NULL);
 
43259
        DUK_ASSERT(func->fnum_next == 0);
 
43260
 
 
43261
        duk_push_array(ctx);
 
43262
        func->decls_idx = entry_top + 3;
 
43263
        func->h_decls = duk_get_hobject(ctx, entry_top + 3);
 
43264
        DUK_ASSERT(func->h_decls != NULL);
 
43265
 
 
43266
        duk_push_array(ctx);
 
43267
        func->labelnames_idx = entry_top + 4;
 
43268
        func->h_labelnames = duk_get_hobject(ctx, entry_top + 4);
 
43269
        DUK_ASSERT(func->h_labelnames != NULL);
 
43270
 
 
43271
        duk_push_dynamic_buffer(ctx, 0);
 
43272
        func->labelinfos_idx = entry_top + 5;
 
43273
        func->h_labelinfos = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 5);
 
43274
        DUK_ASSERT(func->h_labelinfos != NULL);
 
43275
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos));
 
43276
 
 
43277
        duk_push_array(ctx);
 
43278
        func->argnames_idx = entry_top + 6;
 
43279
        func->h_argnames = duk_get_hobject(ctx, entry_top + 6);
 
43280
        DUK_ASSERT(func->h_argnames != NULL);
 
43281
 
 
43282
        duk_push_object_internal(ctx);
 
43283
        func->varmap_idx = entry_top + 7;
 
43284
        func->h_varmap = duk_get_hobject(ctx, entry_top + 7);
 
43285
        DUK_ASSERT(func->h_varmap != NULL);
 
43286
}
 
43287
 
 
43288
/* reset function state (prepare for pass 2) */
 
43289
static void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
 
43290
        duk_compiler_func *func = &comp_ctx->curr_func;
 
43291
        duk_hthread *thr = comp_ctx->thr;
 
43292
 
 
43293
        /* FIXME: reset buffers while keeping existing spare */
 
43294
 
 
43295
        duk_hbuffer_reset(thr, func->h_code);
 
43296
        duk_hobject_set_length_zero(thr, func->h_consts);
 
43297
        /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
 
43298
        func->fnum_next = 0;
 
43299
        /* duk_hobject_set_length_zero(thr, func->h_funcs); */
 
43300
        duk_hobject_set_length_zero(thr, func->h_labelnames);
 
43301
        duk_hbuffer_reset(thr, func->h_labelinfos);
 
43302
        /* keep func->h_argnames; it is fixed for all passes */
 
43303
}
 
43304
 
 
43305
/* cleanup varmap from any null entries, compact it, etc; returns number
 
43306
 * of final entries after cleanup.
 
43307
 */
 
43308
static int duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
 
43309
        duk_hthread *thr = comp_ctx->thr;
 
43310
        duk_context *ctx = (duk_context *) thr;
 
43311
        duk_hobject *h_varmap;
 
43312
        duk_hstring *h_key;
 
43313
        duk_tval *tv;
 
43314
        int i, e_used;
 
43315
        int ret;
 
43316
 
 
43317
        /* [ ... varmap ] */
 
43318
 
 
43319
        h_varmap = duk_get_hobject(ctx, -1);
 
43320
        DUK_ASSERT(h_varmap != NULL);
 
43321
 
 
43322
        ret = 0;
 
43323
        e_used = h_varmap->e_used;
 
43324
        for (i = 0; i < e_used; i++) {
 
43325
                h_key = DUK_HOBJECT_E_GET_KEY(h_varmap, i);
 
43326
                if (!h_key) {
 
43327
                        continue;
 
43328
                }
 
43329
 
 
43330
                DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h_varmap, i));
 
43331
 
 
43332
                /* The entries can either be register numbers or 'null' values.
 
43333
                 * Thus, no need to DECREF them and get side effects.  DECREF'ing
 
43334
                 * the keys (strings) can cause memory to be freed but no side
 
43335
                 * effects as strings don't have finalizers.  This is why we can
 
43336
                 * rely on the object properties not changing from underneath us.
 
43337
                 */
 
43338
 
 
43339
                tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(h_varmap, i);
 
43340
                if (!DUK_TVAL_IS_NUMBER(tv)) {
 
43341
                        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
 
43342
                        DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
43343
                        DUK_HOBJECT_E_SET_KEY(h_varmap, i, NULL);
 
43344
                        DUK_HSTRING_DECREF(thr, h_key);
 
43345
                } else {
 
43346
                        ret++;
 
43347
                }
 
43348
        }
 
43349
 
 
43350
        duk_compact(ctx, -1);
 
43351
 
 
43352
        return ret;
 
43353
}
 
43354
 
 
43355
/* convert duk_compiler_func into a function template, leaving the result
 
43356
 * on top of stack.
 
43357
 */
 
43358
/* FIXME: awkward and bloated asm -- use faster internal accesses */
 
43359
static void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
 
43360
        duk_compiler_func *func = &comp_ctx->curr_func;
 
43361
        duk_hthread *thr = comp_ctx->thr;
 
43362
        duk_context *ctx = (duk_context *) thr;
 
43363
        duk_hcompiledfunction *h_res;
 
43364
        duk_hbuffer_fixed *h_data;
 
43365
        size_t consts_count;
 
43366
        size_t funcs_count;
 
43367
        size_t code_count;
 
43368
        size_t code_size;
 
43369
        size_t data_size;
 
43370
        size_t i;
 
43371
        duk_tval *p_const;
 
43372
        duk_hobject **p_func;
 
43373
        duk_instr *p_instr;
 
43374
        duk_compiler_instr *q_instr;
 
43375
        duk_tval *tv;
 
43376
 
 
43377
        DUK_DDDPRINT("converting duk_compiler_func to function/template");
 
43378
        DUK_DDPRINT("code=%!xO consts=%!O funcs=%!O", func->h_code, func->h_consts, func->h_funcs);
 
43379
 
 
43380
        /*
 
43381
         *  Push result object and init its flags
 
43382
         */
 
43383
 
 
43384
        /* Valstack should suffice here, required on function valstack init */
 
43385
 
 
43386
        (void) duk_push_compiledfunction(ctx);
 
43387
        h_res = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);  /* FIXME: specific getter */
 
43388
 
 
43389
        if (func->is_function) {
 
43390
                DUK_DDDPRINT("function -> set NEWENV");
 
43391
                DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
 
43392
 
 
43393
                if (!func->is_arguments_shadowed) {
 
43394
                        /* arguments object would be accessible; note that shadowing
 
43395
                         * bindings are arguments or function declarations, neither
 
43396
                         * of which are deletable, so this is safe.
 
43397
                         */
 
43398
 
 
43399
                        if (func->id_access_arguments || func->may_direct_eval) {
 
43400
                                DUK_DDDPRINT("function may access 'arguments' object directly or "
 
43401
                                             "indirectly -> set CREATEARGS");
 
43402
                                DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
 
43403
                        }
 
43404
                }
 
43405
        } else if (func->is_eval && func->is_strict) {
 
43406
                DUK_DDDPRINT("strict eval code -> set NEWENV");
 
43407
                DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
 
43408
        } else {
 
43409
                /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
 
43410
                 * global code: env is is global env
 
43411
                 */
 
43412
                DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV");
 
43413
                DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
 
43414
        }
 
43415
 
 
43416
        if (func->is_function && !func->is_decl && func->h_name != NULL) {
 
43417
                DUK_DDDPRINT("function expression with a name -> set NAMEBINDING");
 
43418
                DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
 
43419
        }
 
43420
 
 
43421
        if (func->is_strict) {
 
43422
                DUK_DDDPRINT("function is strict -> set STRICT");
 
43423
                DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
 
43424
        }
 
43425
 
 
43426
        /*
 
43427
         *  Build function fixed size 'data' buffer, which contains bytecode,
 
43428
         *  constants, and inner function references.
 
43429
         *
 
43430
         *  During the building phase 'data' is reachable but incomplete.
 
43431
         *  Only incref's occur during building (no refzero or GC happens),
 
43432
         *  so the building process is atomic.
 
43433
         */
 
43434
 
 
43435
        consts_count = duk_hobject_get_length(comp_ctx->thr, func->h_consts);
 
43436
        funcs_count = duk_hobject_get_length(comp_ctx->thr, func->h_funcs) / 3;
 
43437
        code_count = DUK_HBUFFER_GET_SIZE(func->h_code) / sizeof(duk_compiler_instr);
 
43438
        code_size = code_count * sizeof(duk_instr);
 
43439
 
 
43440
        data_size = consts_count * sizeof(duk_tval) +
 
43441
                    funcs_count * sizeof(duk_hobject *) +
 
43442
                    code_size;
 
43443
 
 
43444
        DUK_DDDPRINT("consts_count=%d, funcs_count=%d, code_size=%d -> "
 
43445
                     "data_size=%d*%d + %d*%d + %d = %d",
 
43446
                     (int) consts_count, (int) funcs_count, (int) code_size,
 
43447
                     (int) consts_count, (int) sizeof(duk_tval),
 
43448
                     (int) funcs_count, (int) sizeof(duk_hobject *),
 
43449
                     (int) code_size, (int) data_size);
 
43450
 
 
43451
        duk_push_fixed_buffer(ctx, data_size);
 
43452
        h_data = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
 
43453
        DUK_ASSERT(h_data != NULL);
 
43454
 
 
43455
        h_res->data = (duk_hbuffer *) h_data;
 
43456
        DUK_HEAPHDR_INCREF(thr, h_data);
 
43457
 
 
43458
        p_const = (duk_tval *) DUK_HBUFFER_FIXED_GET_DATA_PTR(h_data);
 
43459
        for (i = 0; i < consts_count; i++) {
 
43460
                tv = duk_hobject_find_existing_array_entry_tval_ptr(func->h_consts, i);
 
43461
                DUK_ASSERT(tv != NULL);
 
43462
                DUK_TVAL_SET_TVAL(p_const, tv);
 
43463
                p_const++;
 
43464
                DUK_TVAL_INCREF(thr, tv);  /* may be a string constant */
 
43465
 
 
43466
                DUK_DDDPRINT("constant: %!T", tv);
 
43467
        }
 
43468
 
 
43469
        p_func = (duk_hobject **) p_const;
 
43470
        h_res->funcs = p_func;
 
43471
        for (i = 0; i < funcs_count; i++) {
 
43472
                duk_hobject *h;
 
43473
                tv = duk_hobject_find_existing_array_entry_tval_ptr(func->h_funcs, i * 3);
 
43474
                DUK_ASSERT(tv != NULL);
 
43475
                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
43476
                h = DUK_TVAL_GET_OBJECT(tv);
 
43477
                DUK_ASSERT(h != NULL);
 
43478
                DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h));
 
43479
                *p_func++ = h;
 
43480
                DUK_HOBJECT_INCREF(thr, h);
 
43481
 
 
43482
                DUK_DDDPRINT("inner function: %p -> %!iO", (void *) h, h);
 
43483
        }
 
43484
 
 
43485
        p_instr = (duk_instr *) p_func;
 
43486
        h_res->bytecode = p_instr;
 
43487
 
 
43488
        /* copy bytecode instructions one at a time */
 
43489
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_code));
 
43490
        q_instr = (duk_compiler_instr *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(func->h_code);
 
43491
        for (i = 0; i < code_count; i++) {
 
43492
                p_instr[i] = q_instr[i].ins;
 
43493
        }
 
43494
        /* Note: 'q_instr' is still used below */
 
43495
 
 
43496
        duk_pop(ctx);  /* 'data' (and everything in it) is reachable through h_res now */
 
43497
 
 
43498
        /*
 
43499
         *  Init object properties
 
43500
         *
 
43501
         *  Properties should be added in decreasing order of access frequency.
 
43502
         *  (Not very critical for function templates.)
 
43503
         */
 
43504
 
 
43505
        DUK_DDDPRINT("init function properties");
 
43506
 
 
43507
        /* [ ... res ] */
 
43508
 
 
43509
        /* _varmap: omitted if function is guaranteed not to do slow path identifier
 
43510
         * accesses or if it would turn out to be empty of actual register mappings
 
43511
         * after a cleanup.
 
43512
         */
 
43513
        if (func->id_access_slow ||     /* directly uses slow accesses */
 
43514
            func->may_direct_eval ||    /* may indirectly slow access through a direct eval */
 
43515
            funcs_count > 0) {          /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
 
43516
                int num_used;
 
43517
                duk_dup(ctx, func->varmap_idx);
 
43518
                num_used = duk__cleanup_varmap(comp_ctx);
 
43519
                DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%d)", duk_get_tval(ctx, -1), num_used);
 
43520
 
 
43521
                if (num_used > 0) {
 
43522
                        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
 
43523
                } else {
 
43524
                        DUK_DDDPRINT("varmap is empty after cleanup -> no need to add");
 
43525
                        duk_pop(ctx);
 
43526
                }
 
43527
        }
 
43528
 
 
43529
        /* _formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
 
43530
        if (1) {  /* FIXME: condition */
 
43531
                /* FIXME: if omitted, recheck handling for 'length' in duk_js_push_closure();
 
43532
                 * it currently relies on _formals being set.
 
43533
                 */
 
43534
                duk_dup(ctx, func->argnames_idx);
 
43535
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
 
43536
        }
 
43537
 
 
43538
        /* name */
 
43539
        if (func->h_name) {
 
43540
                duk_push_hstring(ctx, func->h_name);
 
43541
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
 
43542
        }
 
43543
 
 
43544
        /* _source */
 
43545
#if defined(DUK_USE_FUNC_NONSTD_SOURCE_PROPERTY)
 
43546
        if (0) {
 
43547
                /* FIXME: Currently function source code is not stored, as it is not
 
43548
                 * required by the standard.  Source code should not be stored by
 
43549
                 * default (user should enable it explicitly), and the source should
 
43550
                 * probably be compressed with a trivial text compressor; average
 
43551
                 * compression of 20-30% is quite easy to achieve even with a trivial
 
43552
                 * compressor (RLE + backwards lookup).
 
43553
                 */
 
43554
                /* FIXME: Debugging needs source code to be useful: sometimes input
 
43555
                 * code is not found in files as it may be generated and then eval()'d,
 
43556
                 * given by dynamic C code, etc.
 
43557
                 */
 
43558
 
 
43559
                /*
 
43560
                 *  For global or eval code this is straightforward.  For functions
 
43561
                 *  created with the Function constructor we only get the source for
 
43562
                 *  the body and must manufacture the "function ..." part.
 
43563
                 *
 
43564
                 *  For instance, for constructed functions (v8):
 
43565
                 *
 
43566
                 *    > a = new Function("foo", "bar", "print(foo)");
 
43567
                 *    [Function]
 
43568
                 *    > a.toString()
 
43569
                 *    'function anonymous(foo,bar) {\nprint(foo)\n}'
 
43570
                 *
 
43571
                 *  Similarly for e.g. getters (v8):
 
43572
                 *
 
43573
                 *    > x = { get a(foo,bar) { print(foo); } }
 
43574
                 *    { a: [Getter] }
 
43575
                 *    > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
 
43576
                 *    'function a(foo,bar) { print(foo); }'
 
43577
                 */
 
43578
 
 
43579
                /* FIXME: need tokenizer indices for start and end to substring */
 
43580
                /* FIXME: always normalize function declaration part? */
 
43581
                /* FIXME: if we keep _formals, only need to store body */
 
43582
#if 0
 
43583
                duk_push_string(ctx, "FIXME");
 
43584
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
 
43585
#endif
 
43586
        }
 
43587
#endif  /* DUK_USE_FUNC_NONSTD_SOURCE_PROPERTY */
 
43588
 
 
43589
        /* _pc2line */
 
43590
#if defined(DUK_USE_PC2LINE)
 
43591
        if (1) {
 
43592
                /*
 
43593
                 *  Size-optimized pc->line mapping.
 
43594
                 */
 
43595
 
 
43596
                DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
 
43597
                duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count);  /* -> pushes fixed buffer */
 
43598
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
 
43599
 
 
43600
                /* XXX: if assertions enabled, walk through all valid PCs
 
43601
                 * and check line mapping.
 
43602
                 */
 
43603
        }
 
43604
#endif  /* DUK_USE_PC2LINE */
 
43605
 
 
43606
        /* fileName */
 
43607
        if (comp_ctx->h_filename) {
 
43608
                /*
 
43609
                 *  Source filename (or equivalent), for identifying thrown errors.
 
43610
                 */
 
43611
 
 
43612
                duk_push_hstring(ctx, comp_ctx->h_filename);
 
43613
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
 
43614
        }
 
43615
 
 
43616
        /*
 
43617
         *  Init remaining result fields
 
43618
         *
 
43619
         *  'nregs' controls how large a register frame is allocated.
 
43620
         *
 
43621
         *  'nargs' controls how many formal arguments are written to registers:
 
43622
         *  r0, ... r(nargs-1).  The remaining registers are initialized to
 
43623
         *  undefined.
 
43624
         */
 
43625
 
 
43626
        DUK_ASSERT(func->temp_max >= 0);
 
43627
        h_res->nregs = func->temp_max;
 
43628
        h_res->nargs = duk_hobject_get_length(thr, func->h_argnames);
 
43629
        DUK_ASSERT(h_res->nregs >= h_res->nargs);  /* pass2 allocation handles this */
 
43630
 
 
43631
        DUK_DDPRINT("converted function: %!ixT", duk_get_tval(ctx, -1));
 
43632
 
 
43633
        /*
 
43634
         *  Compact the function template.
 
43635
         */
 
43636
 
 
43637
        duk_compact(ctx, -1);
 
43638
 
 
43639
        /*
 
43640
         *  Debug dumping
 
43641
         */
 
43642
 
 
43643
#ifdef DUK_USE_DDDEBUG
 
43644
        {
 
43645
                duk_hcompiledfunction *h;
 
43646
                duk_instr *p, *p_start, *p_end;
 
43647
 
 
43648
                h = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
 
43649
                p_start = (duk_instr *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(h);
 
43650
                p_end = (duk_instr *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(h);
 
43651
 
 
43652
                p = p_start;
 
43653
                while (p < p_end) {
 
43654
                        DUK_DDDPRINT("BC %04d: %!I        ; 0x%08x op=%d (%!C) a=%d b=%d c=%d",
 
43655
                                     (int) (p - p_start),
 
43656
                                     (*p),
 
43657
                                     (int) (*p),
 
43658
                                     (int) DUK_DEC_OP(*p),
 
43659
                                     (int) DUK_DEC_OP(*p),
 
43660
                                     (int) DUK_DEC_A(*p),
 
43661
                                     (int) DUK_DEC_B(*p),
 
43662
                                     (int) DUK_DEC_C(*p));
 
43663
                        p++;
 
43664
                }
 
43665
        }
 
43666
#endif
 
43667
}
 
43668
 
 
43669
/*
 
43670
 *  Code emission helpers
 
43671
 *
 
43672
 *  Some emission helpers understand the range of target and source reg/const
 
43673
 *  values and automatically emit shuffling code if necessary.  This is the
 
43674
 *  case when the slot in question (A, B, C) is used in the standard way and
 
43675
 *  for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
 
43676
 *
 
43677
 *  The standard way is that:
 
43678
 *    - slot A is a target register
 
43679
 *    - slot B is a source register/constant
 
43680
 *    - slot C is a source register/constant
 
43681
 *
 
43682
 *  If a slot is used in a non-standard way the caller must indicate this
 
43683
 *  somehow.  If a slot is used as a target instead of a source (or vice
 
43684
 *  versa), this can be indicated with a flag to trigger proper shuffling
 
43685
 *  (e.g. DUK__EMIT_FLAG_B_IS_TARGET).  If the value in the slot is not
 
43686
 *  register/const related at all, the caller must ensure that the raw value
 
43687
 *  fits into the corresponding slot so as to not trigger shuffling.  The
 
43688
 *  caller must set a "no shuffle" flag to ensure compilation fails if
 
43689
 *  shuffling were to be triggered because of an internal error.
 
43690
 *
 
43691
 *  For slots B and C the raw slot size is 9 bits but one bit is reserved for
 
43692
 *  the reg/const indicator.  To use the full 9-bit range for a raw value,
 
43693
 *  shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
 
43694
 *  Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
 
43695
 *
 
43696
 *  There is call handling specific understanding in the A-B-C emitter to
 
43697
 *  convert call setup and call instructions into indirect ones if necessary.
 
43698
 */
 
43699
 
 
43700
/* Code emission flags, passed in the 'opcode' field */
 
43701
#define DUK__EMIT_FLAG_NO_SHUFFLE_A  (1 << 8)
 
43702
#define DUK__EMIT_FLAG_NO_SHUFFLE_B  (1 << 9)
 
43703
#define DUK__EMIT_FLAG_NO_SHUFFLE_C  (1 << 10)
 
43704
#define DUK__EMIT_FLAG_A_IS_SOURCE   (1 << 11)  /* slot A is a source (default: target) */
 
43705
#define DUK__EMIT_FLAG_B_IS_TARGET   (1 << 12)  /* slot B is a target (default: source) */
 
43706
#define DUK__EMIT_FLAG_C_IS_TARGET   (1 << 13)  /* slot C is a target (default: source) */
 
43707
 
 
43708
/* FIXME: clarify on when and where DUK__CONST_MARKER is allowed */
 
43709
/* FIXME: opcode specific assertions on when consts are allowed */
 
43710
 
 
43711
/* FIXME: macro smaller than call? */
 
43712
static int duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
 
43713
        return DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_code) / sizeof(duk_compiler_instr);
 
43714
}
 
43715
 
 
43716
static duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, int pc) {
 
43717
        duk_compiler_func *f = &comp_ctx->curr_func;
 
43718
        char *p;
 
43719
        duk_compiler_instr *code_begin, *code_end;
 
43720
 
 
43721
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(f->h_code);
 
43722
        code_begin = (duk_compiler_instr *) p;
 
43723
        code_end = (duk_compiler_instr *) (p + DUK_HBUFFER_GET_SIZE(f->h_code));
 
43724
        DUK_UNREF(code_end);
 
43725
 
 
43726
        DUK_ASSERT(pc >= 0);
 
43727
        DUK_ASSERT(pc < (code_end - code_begin));
 
43728
 
 
43729
        return &code_begin[pc];
 
43730
}
 
43731
 
 
43732
/* emit instruction; could return PC but that's not needed in the majority
 
43733
 * of cases.
 
43734
 */
 
43735
static void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr ins) {
 
43736
        duk_hbuffer_dynamic *h;
 
43737
#if defined(DUK_USE_PC2LINE)
 
43738
        int line;
 
43739
#endif
 
43740
        duk_compiler_instr instr;
 
43741
 
 
43742
        DUK_DDDPRINT("duk__emit: 0x%08x line=%d pc=%d --> %!I",
 
43743
                     ins, comp_ctx->curr_token.start_line, duk__get_current_pc(comp_ctx), ins);
 
43744
 
 
43745
        h = comp_ctx->curr_func.h_code;
 
43746
#if defined(DUK_USE_PC2LINE)
 
43747
        line = comp_ctx->curr_token.start_line;  /* approximation, close enough */
 
43748
#endif
 
43749
 
 
43750
        instr.ins = ins;
 
43751
#if defined(DUK_USE_PC2LINE)
 
43752
        instr.line = line;
 
43753
#endif
 
43754
 
 
43755
        duk_hbuffer_append_bytes(comp_ctx->thr, h, (duk_uint8_t *) &instr, sizeof(instr));
 
43756
}
 
43757
 
 
43758
#if 0 /* unused */
 
43759
static void duk__emit_op_only(duk_compiler_ctx *comp_ctx, int op) {
 
43760
        duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
 
43761
}
 
43762
#endif
 
43763
 
 
43764
static void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, int op_flags, int a, int b, int c) {
 
43765
        duk_instr ins = 0;
 
43766
        duk_int_t a_out = 0;
 
43767
        duk_int_t b_out = 0;
 
43768
        duk_int_t c_out = 0;
 
43769
        duk_int_t tmp;
 
43770
 
 
43771
        DUK_DDDPRINT("emit: op_flags=%04x, a=%d, b=%d, c=%d",
 
43772
                     (int) op_flags, (int) a, (int) b, (int) c);
 
43773
        
 
43774
        /* We could rely on max temp/const checks: if they don't exceed BC
 
43775
         * limit, nothing here can either (just asserts would be enough).
 
43776
         * Currently we check for the limits, which provides additional
 
43777
         * protection against creating invalid bytecode due to compiler
 
43778
         * bugs.
 
43779
         */
 
43780
 
 
43781
        DUK_ASSERT((op_flags & 0xff) >= DUK_BC_OP_MIN && (op_flags & 0xff) <= DUK_BC_OP_MAX);
 
43782
 
 
43783
        /* Input shuffling happens before the actual operation, while output
 
43784
         * shuffling happens afterwards.  Output shuffling decisions are still
 
43785
         * made at the same time to reduce branch clutter; output shuffle decisions
 
43786
         * are recorded into X_out variables.
 
43787
         */
 
43788
 
 
43789
        /* Slot A */
 
43790
 
 
43791
        if (a <= DUK_BC_A_MAX) {
 
43792
                ;
 
43793
        } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
 
43794
                DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %d", (int) a);
 
43795
                goto error_outofregs;
 
43796
        } else if (a <= DUK_BC_BC_MAX) {
 
43797
                comp_ctx->curr_func.needs_shuffle = 1;
 
43798
                tmp = comp_ctx->curr_func.shuffle1;
 
43799
                if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
 
43800
                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
 
43801
                } else {
 
43802
                        duk_small_int_t op = op_flags & 0xff;
 
43803
                        if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) {
 
43804
                                /* Special handling for call setup instructions.  The target
 
43805
                                 * is expressed indirectly, but there is no output shuffling.
 
43806
                                 */
 
43807
                                DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
 
43808
                                duk__emit_loadint(comp_ctx, tmp, a);
 
43809
                                DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
 
43810
                                DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
 
43811
                                DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
 
43812
                                op_flags++;  /* indirect opcode follows direct */
 
43813
                        } else {
 
43814
                                /* Output shuffle needed after main operation */
 
43815
                                a_out = a;
 
43816
                        }
 
43817
                }
 
43818
                a = tmp;
 
43819
        } else {
 
43820
                DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %d", (int) a);
 
43821
                goto error_outofregs;
 
43822
        }
 
43823
 
 
43824
        /* Slot B */
 
43825
 
 
43826
        if (b & DUK__CONST_MARKER) {
 
43827
                DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
 
43828
                DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
 
43829
                DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
 
43830
                DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
 
43831
                b = b & ~DUK__CONST_MARKER;
 
43832
                if (b <= 0xff) {
 
43833
                        ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0);  /* const flag for B */
 
43834
                } else if (b <= DUK_BC_BC_MAX) {
 
43835
                        comp_ctx->curr_func.needs_shuffle = 1;
 
43836
                        tmp = comp_ctx->curr_func.shuffle2;
 
43837
                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
 
43838
                        b = tmp;
 
43839
                } else {
 
43840
                        DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %d", (int) b);
 
43841
                        goto error_outofregs;
 
43842
                }
 
43843
        } else {
 
43844
                if (b <= 0xff) {
 
43845
                        ;
 
43846
                } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
 
43847
                        if (b > DUK_BC_B_MAX) {
 
43848
                                /* Note: 0xff != DUK_BC_B_MAX */
 
43849
                                DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %d", (int) b);
 
43850
                                goto error_outofregs;
 
43851
                        }
 
43852
                } else if (b <= DUK_BC_BC_MAX) {
 
43853
                        comp_ctx->curr_func.needs_shuffle = 1;
 
43854
                        tmp = comp_ctx->curr_func.shuffle2;
 
43855
                        if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
 
43856
                                /* Output shuffle needed after main operation */
 
43857
                                b_out = b;
 
43858
                        } else {
 
43859
                                duk_small_int_t op = op_flags & 0xff;
 
43860
                                if (op == DUK_OP_CALL || op == DUK_OP_NEW ||
 
43861
                                    op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
 
43862
                                        /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
 
43863
                                         * For each, slot B identifies the first register of a range
 
43864
                                         * of registers, so normal shuffling won't work.  Instead,
 
43865
                                         * an indirect version of the opcode is used.
 
43866
                                         */
 
43867
                                        DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
 
43868
                                        duk__emit_loadint(comp_ctx, tmp, b);
 
43869
                                        DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
 
43870
                                        DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
 
43871
                                        DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
 
43872
                                        DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
 
43873
                                        op_flags++;  /* indirect opcode follows direct */
 
43874
                                } else {
 
43875
                                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
 
43876
                                }
 
43877
                        }
 
43878
                        b = tmp;
 
43879
                } else {
 
43880
                        DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %d", (int) b);
 
43881
                        goto error_outofregs;
 
43882
                }
 
43883
        }
 
43884
 
 
43885
        /* Slot C */
 
43886
 
 
43887
        if (c & DUK__CONST_MARKER) {
 
43888
                DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
 
43889
                DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
 
43890
                c = c & ~DUK__CONST_MARKER;
 
43891
                if (c <= 0xff) {
 
43892
                        ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100);  /* const flag for C */
 
43893
                } else if (c <= DUK_BC_BC_MAX) {
 
43894
                        comp_ctx->curr_func.needs_shuffle = 1;
 
43895
                        tmp = comp_ctx->curr_func.shuffle3;
 
43896
                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
 
43897
                        c = tmp;
 
43898
                } else {
 
43899
                        DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %d", (int) c);
 
43900
                        goto error_outofregs;
 
43901
                }
 
43902
        } else {
 
43903
                if (c <= 0xff) {
 
43904
                        ;
 
43905
                } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
 
43906
                        if (c > DUK_BC_C_MAX) {
 
43907
                                /* Note: 0xff != DUK_BC_C_MAX */
 
43908
                                DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %d", (int) c);
 
43909
                                goto error_outofregs;
 
43910
                        }
 
43911
                } else if (c <= DUK_BC_BC_MAX) {
 
43912
                        comp_ctx->curr_func.needs_shuffle = 1;
 
43913
                        tmp = comp_ctx->curr_func.shuffle3;
 
43914
                        if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
 
43915
                                /* Output shuffle needed after main operation */
 
43916
                                c_out = c;
 
43917
                        } else {
 
43918
                                duk_small_int_t op = op_flags & 0xff;
 
43919
                                if (op == DUK_OP_EXTRA &&
 
43920
                                    (a == DUK_EXTRAOP_INITGET || a == DUK_EXTRAOP_INITSET)) {
 
43921
                                        /* Special shuffling for INITGET/INITSET, where slot C
 
43922
                                         * identifies a register pair and cannot be shuffled
 
43923
                                         * normally.  Use an indirect variant instead.
 
43924
                                         */
 
43925
                                        DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
 
43926
                                        duk__emit_loadint(comp_ctx, tmp, c);
 
43927
                                        DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
 
43928
                                        DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
 
43929
                                        a++;  /* indirect opcode follows direct */
 
43930
                                } else {
 
43931
                                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
 
43932
                                }
 
43933
                        }
 
43934
                        c = tmp;
 
43935
                } else {
 
43936
                        DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %d", (int) c);
 
43937
                        goto error_outofregs;
 
43938
                }
 
43939
        }
 
43940
 
 
43941
        /* Main operation */
 
43942
 
 
43943
        DUK_ASSERT(a >= DUK_BC_A_MIN && a <= DUK_BC_A_MAX);
 
43944
        DUK_ASSERT(b >= DUK_BC_B_MIN && b <= DUK_BC_B_MAX);
 
43945
        DUK_ASSERT(c >= DUK_BC_C_MIN && c <= DUK_BC_C_MAX);
 
43946
 
 
43947
        ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
 
43948
        duk__emit(comp_ctx, ins);
 
43949
 
 
43950
        /* Output shuffling: only one output register is realistically possible. */
 
43951
 
 
43952
        if (a_out != 0) {
 
43953
                DUK_ASSERT(b_out == 0);
 
43954
                DUK_ASSERT(c_out == 0);
 
43955
                duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
 
43956
        } else if (b_out != 0) {
 
43957
                DUK_ASSERT(a_out == 0);
 
43958
                DUK_ASSERT(c_out == 0);
 
43959
                duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
 
43960
        } else if (c_out != 0) {
 
43961
                DUK_ASSERT(b_out == 0);
 
43962
                DUK_ASSERT(c_out == 0);
 
43963
                duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
 
43964
        }
 
43965
 
 
43966
        return;
 
43967
 
 
43968
 error_outofregs:
 
43969
        DUK_ERROR(comp_ctx->thr, DUK_ERR_RANGE_ERROR, "out of regs");
 
43970
}
 
43971
 
 
43972
static void duk__emit_a_b(duk_compiler_ctx *comp_ctx, int op_flags, int a, int b) {
 
43973
        duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
 
43974
}
 
43975
 
 
43976
#if 0  /* unused */
 
43977
static void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
 
43978
        duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
 
43979
}
 
43980
#endif
 
43981
 
 
43982
static void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, int op_flags, int a, int bc) {
 
43983
        duk_instr ins;
 
43984
        duk_int_t tmp;
 
43985
 
 
43986
        /* allow caller to give a const number with the DUK__CONST_MARKER */
 
43987
        bc = bc & (~DUK__CONST_MARKER);
 
43988
 
 
43989
        DUK_ASSERT((op_flags & 0xff) >= DUK_BC_OP_MIN && (op_flags & 0xff) <= DUK_BC_OP_MAX);
 
43990
        DUK_ASSERT(bc >= DUK_BC_BC_MIN && bc <= DUK_BC_BC_MAX);
 
43991
        DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
 
43992
 
 
43993
        if (bc <= DUK_BC_BC_MAX) {
 
43994
                ;
 
43995
        } else {
 
43996
                /* No BC shuffling now. */
 
43997
                goto error_outofregs;
 
43998
        }
 
43999
 
 
44000
        if (a <= DUK_BC_A_MAX) {
 
44001
                ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
 
44002
                duk__emit(comp_ctx, ins);
 
44003
        } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
 
44004
                goto error_outofregs;
 
44005
        } else if (a <= DUK_BC_BC_MAX) {
 
44006
                comp_ctx->curr_func.needs_shuffle = 1;
 
44007
                tmp = comp_ctx->curr_func.shuffle1;
 
44008
                ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
 
44009
                if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
 
44010
                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
 
44011
                        duk__emit(comp_ctx, ins);
 
44012
                } else {
 
44013
                        duk__emit(comp_ctx, ins);
 
44014
                        duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
 
44015
                }
 
44016
        } else {
 
44017
                goto error_outofregs;
 
44018
        }
 
44019
        return;
 
44020
 
 
44021
 error_outofregs:
 
44022
        DUK_ERROR(comp_ctx->thr, DUK_ERR_RANGE_ERROR, "out of regs");
 
44023
}
 
44024
 
 
44025
static void duk__emit_abc(duk_compiler_ctx *comp_ctx, int op, int abc) {
 
44026
        duk_instr ins;
 
44027
 
 
44028
        DUK_ASSERT(op >= DUK_BC_OP_MIN && op <= DUK_BC_OP_MAX);
 
44029
        DUK_ASSERT(abc >= DUK_BC_ABC_MIN && abc <= DUK_BC_ABC_MAX);
 
44030
        DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
 
44031
 
 
44032
        ins = DUK_ENC_OP_ABC(op, abc);
 
44033
        DUK_DDDPRINT("duk__emit_abc: 0x%08x line=%d pc=%d op=%d (%!C) abc=%d (%!I)",
 
44034
                     ins, comp_ctx->curr_token.start_line, duk__get_current_pc(comp_ctx), op, op, abc, ins);
 
44035
        duk__emit(comp_ctx, ins);
 
44036
}
 
44037
 
 
44038
static void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, int extraop_flags, int b, int c) {
 
44039
        DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN &&
 
44040
                   (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
 
44041
        /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
 
44042
        duk__emit_a_b_c(comp_ctx,
 
44043
                        DUK_OP_EXTRA | (extraop_flags & ~0xff),  /* transfer flags */
 
44044
                        extraop_flags & 0xff,
 
44045
                        b,
 
44046
                        c);
 
44047
}
 
44048
 
 
44049
static void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, int extraop_flags, int b) {
 
44050
        DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN &&
 
44051
                   (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
 
44052
        /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
 
44053
        duk__emit_a_b_c(comp_ctx,
 
44054
                        DUK_OP_EXTRA | (extraop_flags & ~0xff),  /* transfer flags */
 
44055
                        extraop_flags & 0xff,
 
44056
                        b,
 
44057
                        0);
 
44058
}
 
44059
 
 
44060
static void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, int extraop, int bc) {
 
44061
        DUK_ASSERT(extraop >= DUK_BC_EXTRAOP_MIN && extraop <= DUK_BC_EXTRAOP_MAX);
 
44062
        /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
 
44063
        duk__emit_a_bc(comp_ctx,
 
44064
                       DUK_OP_EXTRA,
 
44065
                       extraop,
 
44066
                       bc);
 
44067
}
 
44068
 
 
44069
static void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, int extraop_flags) {
 
44070
        DUK_ASSERT((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN &&
 
44071
                   (extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
 
44072
        /* Setting "no shuffle A" would be prudent but not necessary, assert covers it. */
 
44073
        duk__emit_a_b_c(comp_ctx,
 
44074
                        DUK_OP_EXTRA | (extraop_flags & ~0xff),  /* transfer flags */
 
44075
                        extraop_flags & 0xff,
 
44076
                        0,
 
44077
                        0);
 
44078
}
 
44079
 
 
44080
static void duk__emit_loadint(duk_compiler_ctx *comp_ctx, int reg, duk_int32_t val) {
 
44081
        /* FIXME: typing */
 
44082
 
 
44083
        /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
 
44084
         * would only shuffle once (instead of twice).  The current code works
 
44085
         * and has a smaller compiler footprint.
 
44086
         */
 
44087
 
 
44088
        if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
 
44089
            (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
 
44090
                DUK_DDDPRINT("emit LDINT to reg %d for %d", (int) reg, (int) val);
 
44091
                duk__emit_a_bc(comp_ctx, DUK_OP_LDINT, reg, val + (duk_int32_t) DUK_BC_LDINT_BIAS);
 
44092
        } else {
 
44093
                duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
 
44094
                duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
 
44095
                DUK_DDDPRINT("emit LDINT+LDINTX to reg %d for %d -> hi %d, lo %d",
 
44096
                             (int) reg, (int) val, (int) hi, (int) lo);
 
44097
                duk__emit_a_bc(comp_ctx, DUK_OP_LDINT, reg, hi + (duk_int32_t) DUK_BC_LDINT_BIAS);
 
44098
                duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX, reg, lo);
 
44099
        }
 
44100
}
 
44101
 
 
44102
static void duk__emit_jump(duk_compiler_ctx *comp_ctx, int target_pc) {
 
44103
        duk_hbuffer_dynamic *h;
 
44104
        int curr_pc;
 
44105
        int offset;
 
44106
 
 
44107
        h = comp_ctx->curr_func.h_code;
 
44108
        curr_pc = DUK_HBUFFER_GET_SIZE(h) / sizeof(duk_compiler_instr);
 
44109
        offset = target_pc - curr_pc - 1;
 
44110
        DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
 
44111
        DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
 
44112
        duk__emit_abc(comp_ctx, DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
 
44113
}
 
44114
 
 
44115
static int duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
 
44116
        int ret;
 
44117
 
 
44118
        ret = duk__get_current_pc(comp_ctx);  /* useful for patching jumps later */
 
44119
        duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
 
44120
        return ret;
 
44121
}
 
44122
 
 
44123
/* Insert an empty jump in the middle of code emitted earlier.  This is
 
44124
 * currently needed for compiling for-in.
 
44125
 */
 
44126
static void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, int jump_pc) {
 
44127
        duk_hbuffer_dynamic *h;
 
44128
#if defined(DUK_USE_PC2LINE)
 
44129
        int line;
 
44130
#endif
 
44131
        duk_compiler_instr instr;
 
44132
        size_t offset;
 
44133
 
 
44134
        h = comp_ctx->curr_func.h_code;
 
44135
#if defined(DUK_USE_PC2LINE)
 
44136
        line = comp_ctx->curr_token.start_line;  /* approximation, close enough */
 
44137
#endif
 
44138
 
 
44139
        instr.ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
 
44140
#if defined(DUK_USE_PC2LINE)
 
44141
        instr.line = line;
 
44142
#endif
 
44143
 
 
44144
        offset = jump_pc * sizeof(duk_compiler_instr);
 
44145
 
 
44146
        duk_hbuffer_insert_bytes(comp_ctx->thr, h, offset, (duk_uint8_t *) &instr, sizeof(instr));
 
44147
}
 
44148
 
 
44149
/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
 
44150
 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
 
44151
 */
 
44152
static void duk__patch_jump(duk_compiler_ctx *comp_ctx, int jump_pc, int target_pc) {
 
44153
        duk_compiler_instr *instr;
 
44154
        int offset;
 
44155
 
 
44156
        /* allow negative PCs, behave as a no-op */
 
44157
        if (jump_pc < 0) {
 
44158
                DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%d (<0), target_pc=%d", jump_pc, target_pc);
 
44159
                return;
 
44160
        }
 
44161
        DUK_ASSERT(jump_pc >= 0);
 
44162
 
 
44163
        /* FIXME: range assert */
 
44164
        instr = duk__get_instr_ptr(comp_ctx, jump_pc);
 
44165
        DUK_ASSERT(instr != NULL);
 
44166
 
 
44167
        /* FIXME: range assert */
 
44168
        offset = target_pc - jump_pc - 1;
 
44169
 
 
44170
        instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
 
44171
        DUK_DDDPRINT("duk__patch_jump(): jump_pc=%d, target_pc=%d, offset=%d", jump_pc, target_pc, offset);
 
44172
}
 
44173
 
 
44174
static void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, int jump_pc) {
 
44175
        duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
 
44176
}
 
44177
 
 
44178
static void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, int trycatch_pc, int reg_catch, int const_varname, int flags) {
 
44179
        duk_compiler_instr *instr;
 
44180
 
 
44181
        instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
 
44182
        DUK_ASSERT(instr != NULL);
 
44183
 
 
44184
        instr->ins = DUK_ENC_OP_A_B_C(DUK_OP_TRYCATCH, flags, reg_catch, const_varname);
 
44185
}
 
44186
 
 
44187
static void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, int regconst) {
 
44188
        duk__emit_a_b_c(comp_ctx, DUK_OP_IF, 0 /*false*/, regconst, 0);
 
44189
}
 
44190
 
 
44191
static void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, int regconst) {
 
44192
        duk__emit_a_b_c(comp_ctx, DUK_OP_IF, 1 /*true*/, regconst, 0);
 
44193
}
 
44194
 
 
44195
static void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
 
44196
        duk__emit_abc(comp_ctx, DUK_OP_INVALID, 0);
 
44197
}
 
44198
 
 
44199
/*
 
44200
 *  Peephole optimizer for finished bytecode.
 
44201
 *
 
44202
 *  Does not remove opcodes; currently only straightens out unconditional
 
44203
 *  jump chains which are generated by several control structures.
 
44204
 */
 
44205
 
 
44206
static void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
 
44207
        duk_hbuffer_dynamic *h;
 
44208
        duk_compiler_instr *bc;
 
44209
        int iter;
 
44210
        int i, n;
 
44211
        int count_opt;
 
44212
 
 
44213
        h = comp_ctx->curr_func.h_code;
 
44214
        DUK_ASSERT(h != NULL);
 
44215
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
 
44216
 
 
44217
        bc = (duk_compiler_instr *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h);
 
44218
        n = DUK_HBUFFER_GET_SIZE(h) / sizeof(duk_compiler_instr);
 
44219
 
 
44220
        for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
 
44221
                count_opt = 0;
 
44222
 
 
44223
                for (i = 0; i < n; i++) {
 
44224
                        duk_instr ins;
 
44225
                        int target_pc1;
 
44226
                        int target_pc2;
 
44227
 
 
44228
                        ins = bc[i].ins;
 
44229
                        if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
 
44230
                                continue;
 
44231
                        }
 
44232
        
 
44233
                        target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
 
44234
                        DUK_DDDPRINT("consider jump at pc %d; target_pc=%d", i, target_pc1);
 
44235
                        DUK_ASSERT(target_pc1 >= 0);
 
44236
                        DUK_ASSERT(target_pc1 < n);
 
44237
 
 
44238
                        /* Note: if target_pc1 == i, we'll optimize a jump to itself.
 
44239
                         * This does not need to be checked for explicitly; the case
 
44240
                         * is rare and max iter breaks us out.
 
44241
                         */
 
44242
 
 
44243
                        ins = bc[target_pc1].ins;
 
44244
                        if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
 
44245
                                continue;
 
44246
                        }
 
44247
 
 
44248
                        target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
 
44249
 
 
44250
                        DUK_DDDPRINT("optimizing jump at pc %d; old target is %d -> new target is %d",
 
44251
                                     i, target_pc1, target_pc2);
 
44252
 
 
44253
                        bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
 
44254
 
 
44255
                        count_opt++;
 
44256
                }
 
44257
 
 
44258
                DUK_DDPRINT("optimized %d jumps on peephole round %d", count_opt, iter + 1);
 
44259
 
 
44260
                if (count_opt == 0) {
 
44261
                        break;
 
44262
                }
 
44263
        }
 
44264
}
 
44265
 
 
44266
/*
 
44267
 *  Intermediate value helpers
 
44268
 */
 
44269
 
 
44270
#define DUK__ISREG(comp_ctx,x)              (((x) & DUK__CONST_MARKER) == 0)
 
44271
#define DUK__ISCONST(comp_ctx,x)            (((x) & DUK__CONST_MARKER) != 0)
 
44272
#define DUK__ISTEMP(comp_ctx,x)             (DUK__ISREG((comp_ctx), (x)) && (x) >= ((comp_ctx)->curr_func.temp_first))
 
44273
#define DUK__GETTEMP(comp_ctx)              ((comp_ctx)->curr_func.temp_next)
 
44274
#define DUK__SETTEMP(comp_ctx,x)            ((comp_ctx)->curr_func.temp_next = (x))  /* dangerous: must only lower (temp_max not updated) */
 
44275
#define DUK__SETTEMP_CHECKMAX(comp_ctx,x)   duk__settemp_checkmax((comp_ctx),(x))
 
44276
#define DUK__ALLOCTEMP(comp_ctx)            duk__alloctemp((comp_ctx))
 
44277
#define DUK__ALLOCTEMPS(comp_ctx,count)     duk__alloctemps((comp_ctx),(count))
 
44278
 
 
44279
/* Flags for intermediate value coercions.  A flag for using a forced reg
 
44280
 * is not needed, the forced_reg argument suffices and generates better
 
44281
 * code (it is checked as it is used).
 
44282
 */
 
44283
#define DUK__IVAL_FLAG_ALLOW_CONST          (1 << 0)  /* allow a constant to be returned */
 
44284
#define DUK__IVAL_FLAG_REQUIRE_TEMP         (1 << 1)  /* require a (mutable) temporary as a result */
 
44285
#define DUK__IVAL_FLAG_REQUIRE_SHORT        (1 << 2)  /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
 
44286
 
 
44287
/* FIXME: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
 
44288
 
 
44289
static void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
 
44290
        duk_context *ctx = (duk_context *) comp_ctx->thr;
 
44291
 
 
44292
        /* FIXME: use "dup+replace" primitive */
 
44293
        dst->t = src->t;
 
44294
        dst->regconst = src->regconst;
 
44295
        duk_dup(ctx, src->valstack_idx);
 
44296
        duk_replace(ctx, dst->valstack_idx);
 
44297
}
 
44298
 
 
44299
static void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
 
44300
        duk_context *ctx = (duk_context *) comp_ctx->thr;
 
44301
 
 
44302
        /* FIXME: use "dup+replace" primitive */
 
44303
        dst->t = src->t;
 
44304
        dst->op = src->op;
 
44305
        dst->x1.t = src->x1.t;
 
44306
        dst->x1.regconst = src->x1.regconst;
 
44307
        dst->x2.t = src->x2.t;
 
44308
        dst->x2.regconst = src->x2.regconst;
 
44309
        duk_dup(ctx, src->x1.valstack_idx);
 
44310
        duk_replace(ctx, dst->x1.valstack_idx);
 
44311
        duk_dup(ctx, src->x2.valstack_idx);
 
44312
        duk_replace(ctx, dst->x2.valstack_idx);
 
44313
}
 
44314
 
 
44315
/* FIXME: to util */
 
44316
static int duk__is_whole_get_i32(double x, duk_int32_t *ival) {
 
44317
        duk_int32_t t;
 
44318
 
 
44319
        if (DUK_FPCLASSIFY(x) != DUK_FP_NORMAL) {
 
44320
                return 0;
 
44321
        }
 
44322
 
 
44323
        t = (duk_int32_t) x;
 
44324
        if ((double) t == x) {
 
44325
                *ival = t;
 
44326
                return 1;
 
44327
        }
 
44328
 
 
44329
        return 0;
 
44330
}
 
44331
 
 
44332
static int duk__alloctemps(duk_compiler_ctx *comp_ctx, int num) {
 
44333
        int res;
 
44334
 
 
44335
        res = comp_ctx->curr_func.temp_next;
 
44336
        comp_ctx->curr_func.temp_next += num;
 
44337
 
 
44338
        if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) {  /* == DUK__MAX_TEMPS is OK */
 
44339
                DUK_ERROR(comp_ctx->thr, DUK_ERR_INTERNAL_ERROR, "out of temps");
 
44340
        }
 
44341
 
 
44342
        /* maintain highest 'used' temporary, needed to figure out nregs of function */
 
44343
        if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
 
44344
                comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
 
44345
        }
 
44346
 
 
44347
        return res;
 
44348
}
 
44349
 
 
44350
static int duk__alloctemp(duk_compiler_ctx *comp_ctx) {
 
44351
        return duk__alloctemps(comp_ctx, 1);
 
44352
}
 
44353
 
 
44354
static void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, int temp_next) {
 
44355
        comp_ctx->curr_func.temp_next = temp_next;
 
44356
        if (temp_next > comp_ctx->curr_func.temp_max) {
 
44357
                comp_ctx->curr_func.temp_max = temp_next;
 
44358
        }
 
44359
}
 
44360
 
 
44361
/* get const for value at valstack top */
 
44362
static int duk__getconst(duk_compiler_ctx *comp_ctx) {
 
44363
        duk_hthread *thr = comp_ctx->thr;
 
44364
        duk_context *ctx = (duk_context *) thr;
 
44365
        duk_compiler_func *f = &comp_ctx->curr_func;
 
44366
        duk_tval *tv1;
 
44367
        int i, n, n_check;
 
44368
 
 
44369
        n = duk_get_length(ctx, f->consts_idx);
 
44370
 
 
44371
        tv1 = duk_get_tval(ctx, -1);
 
44372
        DUK_ASSERT(tv1 != NULL);
 
44373
 
 
44374
        /* Sanity workaround for handling functions with a large number of
 
44375
         * constants at least somewhat reasonably.  Otherwise checking whether
 
44376
         * we already have the constant would grow very slow (as it is O(N^2)).
 
44377
         */
 
44378
        n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
 
44379
        for (i = 0; i < n_check; i++) {
 
44380
                duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(f->h_consts, i);
 
44381
 
 
44382
                /* Strict equality is NOT enough, because we cannot use the same
 
44383
                 * constant for e.g. +0 and -0.
 
44384
                 */
 
44385
                if (duk_js_samevalue(tv1, tv2)) {
 
44386
                        DUK_DDDPRINT("reused existing constant for %!T -> const index %d", tv1, i);
 
44387
                        duk_pop(ctx);
 
44388
                        return i | DUK__CONST_MARKER;
 
44389
                }
 
44390
        }
 
44391
 
 
44392
        if (n >= DUK__MAX_CONSTS) {
 
44393
                DUK_ERROR(comp_ctx->thr, DUK_ERR_INTERNAL_ERROR, "out of consts");
 
44394
        }
 
44395
 
 
44396
        DUK_DDDPRINT("allocating new constant for %!T -> const index %d", tv1, n);
 
44397
        (void) duk_put_prop_index(ctx, f->consts_idx, n);  /* invalidates tv1, tv2 */
 
44398
        return n | DUK__CONST_MARKER;
 
44399
}
 
44400
 
 
44401
/* Get the value represented by an duk_ispec to a register or constant.
 
44402
 * The caller can control the result by indicating whether or not:
 
44403
 *
 
44404
 *   (1) a constant is allowed (sometimes the caller needs the result to
 
44405
 *       be in a register)
 
44406
 *
 
44407
 *   (2) a temporary register is required (usually when caller requires
 
44408
 *       the register to be safely mutable; normally either a bound
 
44409
 *       register or a temporary register are both OK)
 
44410
 *
 
44411
 *   (3) a forced register target needs to be used
 
44412
 *
 
44413
 * Bytecode may be emitted to generate the necessary value.  The return
 
44414
 * value is either a register or a constant.
 
44415
 */
 
44416
 
 
44417
static int duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
 
44418
                                     duk_ispec *x,
 
44419
                                     int forced_reg,
 
44420
                                     int flags) {
 
44421
        duk_hthread *thr = comp_ctx->thr;
 
44422
        duk_context *ctx = (duk_context *) thr;
 
44423
 
 
44424
        DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%d:%d:%!T}, "
 
44425
                     "forced_reg=%d, flags 0x%08x: allow_const=%d require_temp=%d require_short=%d",
 
44426
                     x->t, x->regconst, duk_get_tval(ctx, x->valstack_idx),
 
44427
                     forced_reg,
 
44428
                     (int) flags,
 
44429
                     (flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0,
 
44430
                     (flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0,
 
44431
                     (flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0);
 
44432
 
 
44433
        switch (x->t) {
 
44434
        case DUK_ISPEC_VALUE: {
 
44435
                duk_tval *tv;
 
44436
 
 
44437
                tv = duk_get_tval(ctx, x->valstack_idx);
 
44438
                DUK_ASSERT(tv != NULL);
 
44439
 
 
44440
                switch (DUK_TVAL_GET_TAG(tv)) {
 
44441
                case DUK_TAG_UNDEFINED: {
 
44442
                        /* Note: although there is no 'undefined' literal, undefined
 
44443
                         * values can occur during compilation as a result of e.g.
 
44444
                         * the 'void' operator.
 
44445
                         */
 
44446
                        int dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44447
                        duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, dest);
 
44448
                        return dest; 
 
44449
                }
 
44450
                case DUK_TAG_NULL: {
 
44451
                        int dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44452
                        duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDNULL, dest);
 
44453
                        return dest;
 
44454
                }
 
44455
                case DUK_TAG_BOOLEAN: {
 
44456
                        int dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44457
                        duk__emit_extraop_bc(comp_ctx,
 
44458
                                             (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_EXTRAOP_LDTRUE : DUK_EXTRAOP_LDFALSE),
 
44459
                                             dest);
 
44460
                        return dest;
 
44461
                }
 
44462
                case DUK_TAG_POINTER: {
 
44463
                        DUK_UNREACHABLE();
 
44464
                        break;
 
44465
                }
 
44466
                case DUK_TAG_STRING: {
 
44467
                        duk_hstring *h;
 
44468
                        int dest;
 
44469
                        int constidx;
 
44470
 
 
44471
                        h = DUK_TVAL_GET_STRING(tv);
 
44472
                        DUK_UNREF(h);
 
44473
                        DUK_ASSERT(h != NULL);
 
44474
 
 
44475
#if 0  /* FIXME: to be implemented? */
 
44476
                        /* Use special opcodes to load short strings */
 
44477
                        if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
 
44478
                                /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
 
44479
                        } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
 
44480
                                /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
 
44481
                        }
 
44482
#endif
 
44483
                        duk_dup(ctx, x->valstack_idx);
 
44484
                        constidx = duk__getconst(comp_ctx);
 
44485
 
 
44486
                        if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
 
44487
                                return constidx;
 
44488
                        }
 
44489
 
 
44490
                        dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44491
                        duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
 
44492
                        return dest;
 
44493
                }
 
44494
                case DUK_TAG_OBJECT: {
 
44495
                        DUK_UNREACHABLE();
 
44496
                        break;
 
44497
                }
 
44498
                case DUK_TAG_BUFFER: {
 
44499
                        DUK_UNREACHABLE();
 
44500
                        break;
 
44501
                }
 
44502
                default: {
 
44503
                        /* number */
 
44504
                        int constidx;
 
44505
                        int dest;
 
44506
                        double dval;
 
44507
                        duk_int32_t ival;
 
44508
 
 
44509
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
44510
                        dval = DUK_TVAL_GET_NUMBER(tv);
 
44511
 
 
44512
                        if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
 
44513
                                /* A number can be loaded either through a constant, using
 
44514
                                 * LDINT, or using LDINT+LDINTX.  LDINT is always a size win,
 
44515
                                 * LDINT+LDINTX is not if the constant is used multiple times.
 
44516
                                 * Currently always prefer LDINT+LDINTX over a double constant.
 
44517
                                 */
 
44518
 
 
44519
                                if (duk__is_whole_get_i32(dval, &ival)) {
 
44520
                                        dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44521
                                        duk__emit_loadint(comp_ctx, dest, ival);
 
44522
                                        return dest;
 
44523
                                }
 
44524
                        }
 
44525
 
 
44526
                        duk_dup(ctx, x->valstack_idx);
 
44527
                        constidx = duk__getconst(comp_ctx);
 
44528
 
 
44529
                        if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
 
44530
                                return constidx;
 
44531
                        } else {
 
44532
                                dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44533
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
 
44534
                                return dest;
 
44535
                        }
 
44536
                }
 
44537
                }  /* end switch */
 
44538
        }
 
44539
        case DUK_ISPEC_REGCONST: {
 
44540
                if ((x->regconst & DUK__CONST_MARKER) && !(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
 
44541
                        int dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44542
                        duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
 
44543
                        return dest;
 
44544
                } else {
 
44545
                        if (forced_reg >= 0) {
 
44546
                                if (x->regconst != forced_reg) {
 
44547
                                        duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
 
44548
                                }
 
44549
                                return forced_reg;
 
44550
                        } else {
 
44551
                                if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
 
44552
                                        int dest = DUK__ALLOCTEMP(comp_ctx);
 
44553
                                        duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
 
44554
                                        return dest;
 
44555
                                } else {
 
44556
                                        return x->regconst;
 
44557
                                }
 
44558
                        }
 
44559
                }
 
44560
        }
 
44561
        default: {
 
44562
                break;
 
44563
        }
 
44564
        }
 
44565
 
 
44566
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "duk__ispec_toregconst_raw() internal error");
 
44567
        return 0;       /* FIXME: notreached */
 
44568
}
 
44569
 
 
44570
static int duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, int forced_reg) {
 
44571
        return duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
 
44572
}
 
44573
 
 
44574
/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
 
44575
 * arithmetic operations, property access, or variable access bytecode.
 
44576
 * The duk_ivalue argument ('x') is converted into a plain value as a
 
44577
 * side effect.
 
44578
 */
 
44579
static void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg) {
 
44580
        duk_hthread *thr = comp_ctx->thr;
 
44581
        duk_context *ctx = (duk_context *) thr;
 
44582
 
 
44583
        DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%d,op=%d,x1={%d:%d:%!T},x2={%d:%d:%!T}}, "
 
44584
                     "forced_reg=%d",
 
44585
                     x->t, x->op,
 
44586
                     x->x1.t, x->x1.regconst, duk_get_tval(ctx, x->x1.valstack_idx),
 
44587
                     x->x2.t, x->x2.regconst, duk_get_tval(ctx, x->x2.valstack_idx),
 
44588
                     forced_reg);
 
44589
 
 
44590
        switch (x->t) {
 
44591
        case DUK_IVAL_PLAIN: {
 
44592
                return;
 
44593
        }
 
44594
        /* FIXME: support unary arithmetic ivalues (useful?) */
 
44595
        case DUK_IVAL_ARITH: {
 
44596
                int arg1;
 
44597
                int arg2;
 
44598
                int dest;
 
44599
                duk_tval *tv1;
 
44600
                duk_tval *tv2;
 
44601
 
 
44602
                DUK_DDDPRINT("arith to plain conversion");
 
44603
 
 
44604
                /* inline arithmetic check for constant values */
 
44605
                /* FIXME: use the exactly same arithmetic function here as in executor */
 
44606
                if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE) {
 
44607
                        tv1 = duk_get_tval(ctx, x->x1.valstack_idx);
 
44608
                        tv2 = duk_get_tval(ctx, x->x2.valstack_idx);
 
44609
                        DUK_ASSERT(tv1 != NULL);
 
44610
                        DUK_ASSERT(tv2 != NULL);
 
44611
 
 
44612
                        DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T", tv1, tv2);
 
44613
 
 
44614
                        if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
 
44615
                                double d1 = DUK_TVAL_GET_NUMBER(tv1);
 
44616
                                double d2 = DUK_TVAL_GET_NUMBER(tv2);
 
44617
                                double d3;
 
44618
                                int accept = 1;
 
44619
 
 
44620
                                DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%d", d1, d2, x->op);
 
44621
                                switch (x->op) {
 
44622
                                case DUK_OP_ADD:        d3 = d1 + d2; break;
 
44623
                                case DUK_OP_SUB:        d3 = d1 - d2; break;
 
44624
                                case DUK_OP_MUL:        d3 = d1 * d2; break;
 
44625
                                case DUK_OP_DIV:        d3 = d1 / d2; break;
 
44626
                                default:                accept = 0; break;
 
44627
                                }
 
44628
 
 
44629
                                if (accept) {
 
44630
                                        duk_double_union du;
 
44631
                                        du.d = d3;
 
44632
                                        DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
44633
                                        d3 = du.d;
 
44634
 
 
44635
                                        x->t = DUK_IVAL_PLAIN;
 
44636
                                        DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
 
44637
                                        DUK_TVAL_SET_NUMBER(tv1, d3);  /* old value is number: no refcount */
 
44638
                                        return;
 
44639
                                }
 
44640
                        } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
 
44641
                                /* inline string concatenation */
 
44642
                                duk_dup(ctx, x->x1.valstack_idx);
 
44643
                                duk_dup(ctx, x->x2.valstack_idx);
 
44644
                                duk_concat(ctx, 2);
 
44645
                                duk_replace(ctx, x->x1.valstack_idx);
 
44646
                                x->t = DUK_IVAL_PLAIN;
 
44647
                                DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
 
44648
                                return;
 
44649
                        }
 
44650
                }
 
44651
 
 
44652
                arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
 
44653
                arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
 
44654
 
 
44655
                /* If forced reg, use it as destination.  Otherwise try to
 
44656
                 * use either coerced ispec if it is a temporary.
 
44657
                 */
 
44658
                if (forced_reg >= 0) {
 
44659
                        dest = forced_reg;
 
44660
                } else if (DUK__ISTEMP(comp_ctx, arg1)) {
 
44661
                        dest = arg1;
 
44662
                } else if (DUK__ISTEMP(comp_ctx, arg2)) {
 
44663
                        dest = arg2;
 
44664
                } else {
 
44665
                        dest = DUK__ALLOCTEMP(comp_ctx);
 
44666
                }
 
44667
 
 
44668
                duk__emit_a_b_c(comp_ctx, x->op, dest, arg1, arg2);
 
44669
 
 
44670
                x->t = DUK_IVAL_PLAIN;
 
44671
                x->x1.t = DUK_ISPEC_REGCONST;
 
44672
                x->x1.regconst = dest;
 
44673
                return;
 
44674
        }
 
44675
        case DUK_IVAL_PROP: {
 
44676
                /* FIXME: very similar to DUK_IVAL_ARITH - merge? */
 
44677
                int arg1;
 
44678
                int arg2;
 
44679
                int dest;
 
44680
 
 
44681
                /* need a short reg/const, does not have to be a mutable temp */
 
44682
                arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
 
44683
                arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
 
44684
 
 
44685
                if (forced_reg >= 0) {
 
44686
                        dest = forced_reg;
 
44687
                } else if (DUK__ISTEMP(comp_ctx, arg1)) {
 
44688
                        dest = arg1;
 
44689
                } else if (DUK__ISTEMP(comp_ctx, arg2)) {
 
44690
                        dest = arg2;
 
44691
                } else {
 
44692
                        dest = DUK__ALLOCTEMP(comp_ctx);
 
44693
                }
 
44694
 
 
44695
                duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, dest, arg1, arg2);
 
44696
 
 
44697
                x->t = DUK_IVAL_PLAIN;
 
44698
                x->x1.t = DUK_ISPEC_REGCONST;
 
44699
                x->x1.regconst = dest;
 
44700
                return;
 
44701
        }
 
44702
        case DUK_IVAL_VAR: {
 
44703
                /* x1 must be a string */
 
44704
                int dest;
 
44705
                int reg_varbind;
 
44706
                int reg_varname;
 
44707
 
 
44708
                DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
 
44709
 
 
44710
                duk_dup(ctx, x->x1.valstack_idx);
 
44711
                if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
44712
                        x->t = DUK_IVAL_PLAIN;
 
44713
                        x->x1.t = DUK_ISPEC_REGCONST;
 
44714
                        x->x1.regconst = reg_varbind;
 
44715
                } else {
 
44716
                        dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
 
44717
                        duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, reg_varname);
 
44718
                        x->t = DUK_IVAL_PLAIN;
 
44719
                        x->x1.t = DUK_ISPEC_REGCONST;
 
44720
                        x->x1.regconst = dest;
 
44721
                }
 
44722
                return;
 
44723
        }
 
44724
        case DUK_IVAL_NONE:
 
44725
        default: {
 
44726
                break;
 
44727
        }
 
44728
        }
 
44729
 
 
44730
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "duk__ivalue_toplain_raw() internal error");
 
44731
        return; /* FIXME: unreachable */
 
44732
}
 
44733
 
 
44734
/* evaluate to plain value, no forced register (temp/bound reg both ok) */
 
44735
static void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
 
44736
        duk__ivalue_toplain_raw(comp_ctx, x, -1);  /* no forced reg */
 
44737
}
 
44738
 
 
44739
/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
 
44740
static void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
 
44741
        int temp;
 
44742
        temp = DUK__GETTEMP(comp_ctx);
 
44743
        duk__ivalue_toplain_raw(comp_ctx, x, -1);  /* no forced reg */
 
44744
        DUK__SETTEMP(comp_ctx, temp);
 
44745
}
 
44746
 
 
44747
/* Coerce an duk_ivalue to a register or constant; result register may
 
44748
 * be a temp or a bound register.
 
44749
 *
 
44750
 * The duk_ivalue argument ('x') is converted into a regconst as a
 
44751
 * side effect.
 
44752
 */
 
44753
static int duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
 
44754
                                      duk_ivalue *x,
 
44755
                                      int forced_reg,
 
44756
                                      int flags) {
 
44757
        duk_hthread *thr = comp_ctx->thr;
 
44758
        duk_context *ctx = (duk_context *) thr;
 
44759
        int reg;
 
44760
        DUK_UNREF(thr);
 
44761
        DUK_UNREF(ctx);
 
44762
 
 
44763
        DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%d,op=%d,x1={%d:%d:%!T},x2={%d:%d:%!T}}, "
 
44764
                     "forced_reg=%d, flags 0x%08x: allow_const=%d require_temp=%d require_short=%d",
 
44765
                     x->t, x->op,
 
44766
                     x->x1.t, x->x1.regconst, duk_get_tval(ctx, x->x1.valstack_idx),
 
44767
                     x->x2.t, x->x2.regconst, duk_get_tval(ctx, x->x2.valstack_idx),
 
44768
                     forced_reg,
 
44769
                     (int) flags,
 
44770
                     (flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0,
 
44771
                     (flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0,
 
44772
                     (flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0);
 
44773
 
 
44774
        /* first coerce to a plain value */
 
44775
        duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
 
44776
        DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
 
44777
 
 
44778
        /* then to a register */
 
44779
        reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
 
44780
        x->x1.t = DUK_ISPEC_REGCONST;
 
44781
        x->x1.regconst = reg;
 
44782
 
 
44783
        return reg;
 
44784
}
 
44785
 
 
44786
static int duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
 
44787
        return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
 
44788
}
 
44789
 
 
44790
#if 0  /* unused */
 
44791
static int duk__ivalue_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
 
44792
        return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
 
44793
}
 
44794
#endif
 
44795
 
 
44796
static int duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, int forced_reg) {
 
44797
        return duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
 
44798
}
 
44799
 
 
44800
static int duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
 
44801
        return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
44802
}
 
44803
 
 
44804
/* The issues below can be solved with better flags */
 
44805
 
 
44806
/* FIXME: many operations actually want toforcedtemp() -- brand new temp? */
 
44807
/* FIXME: need a toplain_ignore() which will only coerce a value to a temp
 
44808
 * register if it might have a side effect.  Side-effect free values do not
 
44809
 * need to be coerced.
 
44810
 */
 
44811
 
 
44812
/*
 
44813
 *  Identifier handling
 
44814
 */
 
44815
 
 
44816
static int duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
 
44817
        duk_hthread *thr = comp_ctx->thr;
 
44818
        duk_context *ctx = (duk_context *) thr;
 
44819
        duk_hstring *h_varname;
 
44820
        int ret;
 
44821
 
 
44822
        DUK_DDDPRINT("resolving identifier reference to '%!T'", duk_get_tval(ctx, -1));
 
44823
 
 
44824
        /*
 
44825
         *  Special name handling
 
44826
         */
 
44827
 
 
44828
        h_varname = duk_get_hstring(ctx, -1);
 
44829
        DUK_ASSERT(h_varname != NULL);
 
44830
 
 
44831
        if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
 
44832
                DUK_DDDPRINT("flagging function as accessing 'arguments'");
 
44833
                comp_ctx->curr_func.id_access_arguments = 1;
 
44834
        }
 
44835
 
 
44836
        /*
 
44837
         *  Inside one or more 'with' statements fall back to slow path always.
 
44838
         *  (See e.g. test-stmt-with.js.)
 
44839
         */
 
44840
 
 
44841
        if (comp_ctx->curr_func.with_depth > 0) {
 
44842
                DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path");
 
44843
                goto slow_path;
 
44844
        }
 
44845
 
 
44846
        /*
 
44847
         *  Any catch bindings ("catch (e)") also affect identifier binding.
 
44848
         *
 
44849
         *  Currently, the varmap is modified for the duration of the catch
 
44850
         *  clause to ensure any identifier accesses with the catch variable
 
44851
         *  name will use slow path.
 
44852
         */
 
44853
 
 
44854
        duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
44855
        if (duk_is_number(ctx, -1)) {
 
44856
                ret = duk_to_int(ctx, -1);
 
44857
                duk_pop(ctx);
 
44858
        } else {
 
44859
                duk_pop(ctx);
 
44860
                goto slow_path;
 
44861
        }
 
44862
 
 
44863
        DUK_DDDPRINT("identifier lookup -> reg %d", ret);
 
44864
        return ret;
 
44865
 
 
44866
 slow_path:
 
44867
        DUK_DDDPRINT("identifier lookup -> slow path");
 
44868
 
 
44869
        comp_ctx->curr_func.id_access_slow = 1;
 
44870
        return -1;
 
44871
}
 
44872
 
 
44873
/* Lookup an identifier name in the current varmap, indicating whether the
 
44874
 * identifier is register-bound and if not, allocating a constant for the
 
44875
 * identifier name.  Returns 1 if register-bound, 0 otherwise.
 
44876
 */
 
44877
static int duk__lookup_lhs(duk_compiler_ctx *comp_ctx, int *out_reg_varbind, int *out_reg_varname) {
 
44878
        duk_hthread *thr = comp_ctx->thr;
 
44879
        duk_context *ctx = (duk_context *) thr;
 
44880
        int reg_varbind;
 
44881
        int reg_varname;
 
44882
 
 
44883
        /* [ ... varname ] */
 
44884
 
 
44885
        duk_dup_top(ctx);
 
44886
        reg_varbind = duk__lookup_active_register_binding(comp_ctx);
 
44887
 
 
44888
        if (reg_varbind >= 0) {
 
44889
                *out_reg_varbind = reg_varbind;
 
44890
                *out_reg_varname = -1;
 
44891
                duk_pop(ctx);
 
44892
                return 1;
 
44893
        } else {
 
44894
                reg_varname = duk__getconst(comp_ctx);
 
44895
                *out_reg_varbind = -1;
 
44896
                *out_reg_varname = reg_varname;
 
44897
                return 0;
 
44898
        }
 
44899
}
 
44900
 
 
44901
/*
 
44902
 *  Label handling
 
44903
 *
 
44904
 *  Labels are initially added with flags prohibiting both break and continue.
 
44905
 *  When the statement type is finally uncovered (after potentially multiple
 
44906
 *  labels), all the labels are updated to allow/prohibit break and continue.
 
44907
 */
 
44908
 
 
44909
static void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, int pc_label, int label_id) {
 
44910
        duk_hthread *thr = comp_ctx->thr;
 
44911
        duk_context *ctx = (duk_context *) thr;
 
44912
        size_t n;
 
44913
        size_t new_size;
 
44914
        char *p;
 
44915
        duk_labelinfo *li_start, *li;
 
44916
 
 
44917
        /* Duplicate (shadowing) labels are not allowed, except for the empty
 
44918
         * labels (which are used as default labels for switch and iteration
 
44919
         * statements).
 
44920
         *
 
44921
         * We could also allow shadowing of non-empty pending labels without any
 
44922
         * other issues than breaking the required label shadowing requirements
 
44923
         * of the E5 specification, see Section 12.12.
 
44924
         */
 
44925
 
 
44926
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(comp_ctx->curr_func.h_labelinfos);
 
44927
        li_start = (duk_labelinfo *) p;
 
44928
        li = (duk_labelinfo *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
 
44929
        n = (size_t) (li - li_start);
 
44930
 
 
44931
        while (li > li_start) {
 
44932
                li--;
 
44933
 
 
44934
                if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
 
44935
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "duplicate (non-empty) label");
 
44936
                }
 
44937
        }
 
44938
 
 
44939
        /* XXX: awkward */
 
44940
        duk_push_hstring(ctx, h_label);
 
44941
        (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, n);
 
44942
 
 
44943
        new_size = (n + 1) * sizeof(duk_labelinfo);
 
44944
        duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size, new_size);
 
44945
        /* FIXME: spare handling, slow now */
 
44946
 
 
44947
        /* relookup after possible realloc */
 
44948
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(comp_ctx->curr_func.h_labelinfos);
 
44949
        li_start = (duk_labelinfo *) p;
 
44950
        DUK_UNREF(li_start);  /* silence scan-build warning */
 
44951
        li = (duk_labelinfo *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
 
44952
        li--;
 
44953
 
 
44954
        /* Labels need to be recorded as pending before we know whether they will be
 
44955
         * actually be used as part of an iteration statement or a switch statement.
 
44956
         * The flags to allow break/continue are updated when we figure out the
 
44957
         * statement type.
 
44958
         */
 
44959
 
 
44960
        li->flags = 0;
 
44961
        li->label_id = label_id;
 
44962
        li->h_label = h_label;
 
44963
        li->catch_depth = comp_ctx->curr_func.catch_depth;   /* catch depth from current func */
 
44964
        li->pc_label = pc_label;
 
44965
 
 
44966
        DUK_DDDPRINT("registered label: flags=0x%08x, id=%d, name=%!O, catch_depth=%d, pc_label=%d",
 
44967
                     li->flags, li->label_id, li->h_label, li->catch_depth, li->pc_label);
 
44968
}
 
44969
 
 
44970
/* Update all labels with matching label_id. */
 
44971
static void duk__update_label_flags(duk_compiler_ctx *comp_ctx, int label_id, int flags) {
 
44972
        char *p;
 
44973
        duk_labelinfo *li_start, *li;
 
44974
 
 
44975
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(comp_ctx->curr_func.h_labelinfos);
 
44976
        li_start = (duk_labelinfo *) p;
 
44977
        li = (duk_labelinfo *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
 
44978
 
 
44979
        /* Match labels starting from latest; once label_id no longer matches, we can
 
44980
         * safely exit without checking the rest of the labels (only the topmost labels
 
44981
         * are ever updated).
 
44982
         */
 
44983
        while (li > li_start) {
 
44984
                li--;
 
44985
 
 
44986
                if (li->label_id != label_id) {
 
44987
                        break;
 
44988
                }
 
44989
 
 
44990
                DUK_DDDPRINT("updating label flags for li=%p, label_id=%d, flags=%d",
 
44991
                             (void *) li, label_id, flags);
 
44992
 
 
44993
                li->flags = flags;
 
44994
        }
 
44995
}
 
44996
 
 
44997
/* Lookup active label information.  Break/continue distinction is necessary to handle switch
 
44998
 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
 
44999
 *
 
45000
 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
 
45001
 * iteration and switch statements) can.  A break will match the closest unlabelled or labelled
 
45002
 * statement.  A continue will match the closest unlabelled or labelled iteration statement.  It is
 
45003
 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
 
45004
 * be duplicated, the continue cannot match any valid label outside the switch.
 
45005
 *
 
45006
 * A side effect of these rules is that a LABEL statement related to a switch should never actually
 
45007
 * catch a continue abrupt completion at run-time.  Hence an INVALID opcode can be placed in the
 
45008
 * continue slot of the switch's LABEL statement.
 
45009
 */
 
45010
 
 
45011
/* FIXME: awkward, especially the bunch of separate output values -> output struct? */
 
45012
static void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, int is_break, int *out_label_id, int *out_label_catch_depth, int *out_label_pc, int *out_is_closest) {
 
45013
        duk_hthread *thr = comp_ctx->thr;
 
45014
        duk_context *ctx = (duk_context *) thr;
 
45015
        char *p;
 
45016
        duk_labelinfo *li_start, *li_end, *li;
 
45017
        int match = 0;
 
45018
 
 
45019
        DUK_DDDPRINT("looking up active label: label='%!O', is_break=%d", h_label, is_break);
 
45020
 
 
45021
        DUK_UNREF(ctx);
 
45022
 
 
45023
        p = (char *) DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(comp_ctx->curr_func.h_labelinfos);
 
45024
        li_start = (duk_labelinfo *) p;
 
45025
        li_end = (duk_labelinfo *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
 
45026
        li = li_end;
 
45027
 
 
45028
        /* Match labels starting from latest label because there can be duplicate empty
 
45029
         * labels in the label set.
 
45030
         */
 
45031
        while (li > li_start) {
 
45032
                li--;
 
45033
 
 
45034
                if (li->h_label != h_label) {
 
45035
                        DUK_DDDPRINT("labelinfo[%d] ->'%!O' != %!O",
 
45036
                                     (int) (li - li_start), li->h_label, h_label);
 
45037
                        continue;
 
45038
                }
 
45039
 
 
45040
                DUK_DDDPRINT("labelinfo[%d] -> '%!O' label name matches (still need to check type)",
 
45041
                             (int) (li - li_start), h_label);
 
45042
 
 
45043
                /* currently all labels accept a break, so no explicit check for it now */
 
45044
                DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
 
45045
 
 
45046
                if (is_break) {
 
45047
                        /* break matches always */
 
45048
                        match = 1;
 
45049
                        break;
 
45050
                } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
 
45051
                        /* iteration statements allow continue */
 
45052
                        match = 1;
 
45053
                        break;
 
45054
                } else {
 
45055
                        /* continue matched this label -- we can only continue if this is the empty
 
45056
                         * label, for which duplication is allowed, and thus there is hope of
 
45057
                         * finding a match deeper in the label stack.
 
45058
                         */
 
45059
                        if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
 
45060
                                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "continue label matches an invalid statement type");
 
45061
                        } else {
 
45062
                                DUK_DDDPRINT("continue matched an empty label which does not "
 
45063
                                             "allow a continue -> continue lookup deeper in label stack");
 
45064
                        }
 
45065
                }
 
45066
        }
 
45067
        /* FIXME: match flag is awkward, rework */
 
45068
        if (!match) {
 
45069
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "cannot resolve label");
 
45070
        }
 
45071
 
 
45072
        DUK_DDDPRINT("label match: %!O -> label_id %d, catch_depth=%d, pc_label=%d",
 
45073
                     h_label, li->label_id, li->catch_depth, li->pc_label);
 
45074
 
 
45075
        *out_label_id = li->label_id;
 
45076
        *out_label_catch_depth = li->catch_depth;
 
45077
        *out_label_pc = li->pc_label;
 
45078
        *out_is_closest = (li == li_end - 1);
 
45079
}
 
45080
 
 
45081
static void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, int len) {
 
45082
        duk_hthread *thr = comp_ctx->thr;
 
45083
        duk_context *ctx = (duk_context *) thr;
 
45084
        size_t new_size;
 
45085
 
 
45086
        /* FIXME: duk_set_length */
 
45087
        new_size = sizeof(duk_labelinfo) * len;
 
45088
        duk_push_int(ctx, len);
 
45089
        duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
 
45090
        duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size, new_size);  /* FIXME: spare handling */
 
45091
}
 
45092
 
 
45093
/*
 
45094
 *  Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
 
45095
 *
 
45096
 *  - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
 
45097
 *  - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
 
45098
 *  - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
 
45099
 */
 
45100
 
 
45101
/* object literal key tracking flags */
 
45102
#define DUK__OBJ_LIT_KEY_PLAIN  (1 << 0)  /* key encountered as a plain property */
 
45103
#define DUK__OBJ_LIT_KEY_GET    (1 << 1)  /* key encountered as a getter */
 
45104
#define DUK__OBJ_LIT_KEY_SET    (1 << 2)  /* key encountered as a setter */
 
45105
 
 
45106
static void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
45107
        duk_hthread *thr = comp_ctx->thr;
 
45108
        int reg_obj;            /* result reg */
 
45109
        int max_init_values;    /* max # of values initialized in one MPUTARR set */
 
45110
        int temp_start;         /* temp reg value for start of loop */
 
45111
        int num_values;         /* number of values in current MPUTARR set */
 
45112
        int curr_idx;           /* current (next) array index */
 
45113
        int start_idx;          /* start array index of current MPUTARR set */
 
45114
        int init_idx;           /* last array index explicitly initialized, +1 */
 
45115
        int reg_temp;           /* temp reg */
 
45116
        int require_comma;      /* next loop requires a comma */
 
45117
 
 
45118
        /* DUK_TOK_LBRACKET already eaten, current token is right after that */
 
45119
        DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
 
45120
 
 
45121
        max_init_values = DUK__MAX_ARRAY_INIT_VALUES;  /* XXX: depend on available temps? */
 
45122
 
 
45123
        reg_obj = DUK__ALLOCTEMP(comp_ctx);
 
45124
        duk__emit_extraop_b_c(comp_ctx,
 
45125
                              DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET, 
 
45126
                              reg_obj,
 
45127
                              0);  /* XXX: patch initial size afterwards? */
 
45128
        temp_start = DUK__GETTEMP(comp_ctx);
 
45129
 
 
45130
        /*
 
45131
         *  Emit initializers in sets of maximum max_init_values.
 
45132
         *  Corner cases such as single value initializers do not have
 
45133
         *  special handling now.
 
45134
         *
 
45135
         *  Elided elements must not be emitted as 'undefined' values,
 
45136
         *  because such values would be enumerable (which is incorrect).
 
45137
         *  Also note that trailing elisions must be reflected in the
 
45138
         *  length of the final array but cause no elements to be actually
 
45139
         *  inserted.
 
45140
         */
 
45141
 
 
45142
        curr_idx = 0;
 
45143
        init_idx = 0;         /* tracks maximum initialized index + 1 */
 
45144
        start_idx = 0;
 
45145
        require_comma = 0;
 
45146
 
 
45147
        for (;;) {
 
45148
                num_values = 0;
 
45149
                DUK__SETTEMP(comp_ctx, temp_start);
 
45150
 
 
45151
                if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
 
45152
                        break;
 
45153
                }
 
45154
 
 
45155
                for (;;) {
 
45156
                        if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
 
45157
                                /* the outer loop will recheck and exit */
 
45158
                                break;
 
45159
                        }
 
45160
 
 
45161
                        /* comma check */
 
45162
                        if (require_comma) {
 
45163
                                if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
 
45164
                                        /* comma after a value, expected */
 
45165
                                        duk__advance(comp_ctx);
 
45166
                                        require_comma = 0;
 
45167
                                        continue;
 
45168
                                } else {
 
45169
                                        goto syntax_error;
 
45170
                                }
 
45171
                        } else {
 
45172
                                if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
 
45173
                                        /* elision - flush */
 
45174
                                        curr_idx++;
 
45175
                                        duk__advance(comp_ctx);
 
45176
                                        /* if num_values > 0, MPUTARR emitted by outer loop after break */
 
45177
                                        break;
 
45178
                                }
 
45179
                        }
 
45180
                        /* else an array initializer element */
 
45181
 
 
45182
                        /* initial index */
 
45183
                        if (num_values == 0) {
 
45184
                                start_idx = curr_idx;
 
45185
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45186
                                duk__emit_loadint(comp_ctx, reg_temp, start_idx);
 
45187
                        }
 
45188
 
 
45189
                        reg_temp = DUK__ALLOCTEMP(comp_ctx);   /* alloc temp just in case, to update max temp */
 
45190
                        DUK__SETTEMP(comp_ctx, reg_temp);      /* hope that the sub-expression writes to reg_temp */
 
45191
                        duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
 
45192
                        DUK__SETTEMP(comp_ctx, reg_temp + 1);
 
45193
 
 
45194
                        num_values++;
 
45195
                        curr_idx++;
 
45196
                        require_comma = 1;
 
45197
 
 
45198
                        if (num_values >= max_init_values) {
 
45199
                                /* MPUTARR emitted by outer loop */
 
45200
                                break;
 
45201
                        }
 
45202
                }
 
45203
 
 
45204
                if (num_values > 0) {
 
45205
                        /* - A is a source register (it's not a write target, but used
 
45206
                         *   to identify the target object) but can be shuffled.
 
45207
                         * - B cannot be shuffled normally because it identifies a range
 
45208
                         *   of registers, the emitter has special handling for this.
 
45209
                         * - C is a non-register number and cannot be shuffled, but
 
45210
                         *   never needs to be.
 
45211
                         */
 
45212
                        duk__emit_a_b_c(comp_ctx,
 
45213
                                        DUK_OP_MPUTARR |
 
45214
                                            DUK__EMIT_FLAG_NO_SHUFFLE_C |
 
45215
                                            DUK__EMIT_FLAG_A_IS_SOURCE,
 
45216
                                        reg_obj,
 
45217
                                        temp_start,
 
45218
                                        num_values);
 
45219
                        init_idx = start_idx + num_values;
 
45220
#if 0  /* these are not necessary, as they're done at the top of the loop */
 
45221
                        num_values = 0;
 
45222
                        DUK__SETTEMP(comp_ctx, temp_start);
 
45223
#endif
 
45224
                }       
 
45225
        }
 
45226
 
 
45227
        DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
 
45228
        duk__advance(comp_ctx);
 
45229
 
 
45230
        DUK_DDDPRINT("array literal done, curridx=%d, initidx=%d", curr_idx, init_idx);
 
45231
 
 
45232
        /* trailing elisions? */
 
45233
        if (curr_idx > init_idx) {
 
45234
                /* yes, must set array length explicitly */
 
45235
                DUK_DDDPRINT("array literal has trailing elisions which affect its length");
 
45236
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45237
                duk__emit_loadint(comp_ctx, reg_temp, curr_idx);
 
45238
                duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_SETALEN, reg_obj, reg_temp);
 
45239
        }
 
45240
 
 
45241
        DUK__SETTEMP(comp_ctx, temp_start);
 
45242
 
 
45243
        res->t = DUK_IVAL_PLAIN;
 
45244
        res->x1.t = DUK_ISPEC_REGCONST;
 
45245
        res->x1.regconst = reg_obj;
 
45246
        return;
 
45247
 
 
45248
 syntax_error:
 
45249
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid array literal");
 
45250
}
 
45251
 
 
45252
/* duplicate/invalid key checks; returns 1 if syntax error */
 
45253
static int duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, int new_key_flags) {
 
45254
        duk_hthread *thr = comp_ctx->thr;
 
45255
        duk_context *ctx = (duk_context *) thr;
 
45256
        int key_flags;
 
45257
 
 
45258
        /* [ ... key_obj key ] */
 
45259
 
 
45260
        DUK_ASSERT(duk_is_string(ctx, -1));
 
45261
 
 
45262
        /*
 
45263
         *  'key_obj' tracks keys encountered so far by associating an
 
45264
         *  integer with flags with already encountered keys.  The checks
 
45265
         *  below implement E5 Section 11.1.5, step 4 for production:
 
45266
         *
 
45267
         *    PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
 
45268
         */
 
45269
 
 
45270
        duk_dup(ctx, -1);       /* [ ... key_obj key key ] */
 
45271
        duk_get_prop(ctx, -3);  /* [ ... key_obj key val ] */
 
45272
        key_flags = duk_to_int(ctx, -1);
 
45273
        duk_pop(ctx);           /* [ ... key_obj key ] */
 
45274
 
 
45275
        if (new_key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
 
45276
                if ((key_flags & DUK__OBJ_LIT_KEY_PLAIN) && comp_ctx->curr_func.is_strict) {
 
45277
                        /* step 4.a */
 
45278
                        DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode");
 
45279
                        return 1;
 
45280
                }
 
45281
                if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
 
45282
                        /* step 4.c */
 
45283
                        DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter");
 
45284
                        return 1;
 
45285
                }
 
45286
        } else {
 
45287
                if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
 
45288
                        /* step 4.b */
 
45289
                        DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key");
 
45290
                        return 1;
 
45291
                }
 
45292
                if (key_flags & new_key_flags) {
 
45293
                        /* step 4.d */
 
45294
                        DUK_DDDPRINT("duplicate key: getter/setter encountered twice");
 
45295
                        return 1;
 
45296
                }
 
45297
        }
 
45298
 
 
45299
        new_key_flags |= key_flags;
 
45300
        DUK_DDDPRINT("setting/updating key %!T flags: 0x%08x -> 0x%08x",
 
45301
                     duk_get_tval(ctx, -1), key_flags, new_key_flags);
 
45302
        duk_dup(ctx, -1);
 
45303
        duk_push_int(ctx, new_key_flags);   /* [ ... key_obj key key flags ] */
 
45304
        duk_put_prop(ctx, -4);              /* [ ... key_obj key ] */
 
45305
 
 
45306
        return 0;
 
45307
}
 
45308
 
 
45309
static void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
45310
        duk_hthread *thr = comp_ctx->thr;
 
45311
        duk_context *ctx = (duk_context *) thr;
 
45312
        int reg_obj;            /* result reg */
 
45313
        int max_init_pairs;     /* max # of key-value pairs initialized in one MPUTOBJ set */
 
45314
        int temp_start;         /* temp reg value for start of loop */
 
45315
        int num_pairs;          /* number of pairs in current MPUTOBJ set */
 
45316
        int reg_key;            /* temp reg for key literal */
 
45317
        int reg_temp;           /* temp reg */
 
45318
        int first;              /* first value: comma must not precede the value */
 
45319
        int is_set, is_get;     /* temps */
 
45320
 
 
45321
        DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
 
45322
 
 
45323
        max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS;  /* XXX: depend on available temps? */
 
45324
 
 
45325
        reg_obj = DUK__ALLOCTEMP(comp_ctx);
 
45326
        duk__emit_extraop_b_c(comp_ctx,
 
45327
                              DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET,
 
45328
                              reg_obj,
 
45329
                              0);  /* XXX: patch initial size afterwards? */
 
45330
        temp_start = DUK__GETTEMP(comp_ctx);
 
45331
 
 
45332
        /* temp object for tracking / detecting duplicate keys */
 
45333
        duk_push_object(ctx);
 
45334
 
 
45335
        /*
 
45336
         *  Emit initializers in sets of maximum max_init_pairs keys.
 
45337
         *  Setter/getter is handled separately and terminates the
 
45338
         *  current set of initializer values.  Corner cases such as
 
45339
         *  single value initializers do not have special handling now.
 
45340
         */
 
45341
 
 
45342
        first = 1;
 
45343
        for (;;) {
 
45344
                num_pairs = 0;
 
45345
                DUK__SETTEMP(comp_ctx, temp_start);
 
45346
 
 
45347
                if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
 
45348
                        break;
 
45349
                }
 
45350
 
 
45351
                for (;;) {
 
45352
                        /*
 
45353
                         *  Three possible element formats:
 
45354
                         *    1) PropertyName : AssignmentExpression
 
45355
                         *    2) get PropertyName () { FunctionBody }
 
45356
                         *    3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
 
45357
                         *
 
45358
                         *  PropertyName can be IdentifierName (includes reserved words), a string
 
45359
                         *  literal, or a number literal.  Note that IdentifierName allows 'get' and
 
45360
                         *  'set' too, so we need to look ahead to the next token to distinguish:
 
45361
                         *
 
45362
                         *     { get : 1 }
 
45363
                         *
 
45364
                         *  and
 
45365
                         *
 
45366
                         *     { get foo() { return 1 } }
 
45367
                         *     { get get() { return 1 } }    // 'get' as getter propertyname
 
45368
                         *
 
45369
                         *  Finally, a trailing comma is allowed.
 
45370
                         *
 
45371
                         *  Key name is coerced to string at compile time (and ends up as a
 
45372
                         *  a string constant) even for numeric keys (e.g. "{1:'foo'}").
 
45373
                         *  These could be emitted using e.g. LDINT, but that seems hardly
 
45374
                         *  worth the effort and would increase code size.
 
45375
                         */ 
 
45376
 
 
45377
                        DUK_DDDPRINT("object literal inner loop, curr_token->t = %d", comp_ctx->curr_token.t);
 
45378
 
 
45379
                        if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
 
45380
                                /* the outer loop will recheck and exit */
 
45381
                                break;
 
45382
                        }
 
45383
                        if (num_pairs >= max_init_pairs) {
 
45384
                                /* MPUTOBJ emitted by outer loop */
 
45385
                                break;
 
45386
                        }
 
45387
 
 
45388
                        if (first) {
 
45389
                                first = 0;
 
45390
                        } else {
 
45391
                                if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
 
45392
                                        goto syntax_error;
 
45393
                                }
 
45394
                                duk__advance(comp_ctx);
 
45395
                                if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
 
45396
                                        /* trailing comma followed by rcurly */
 
45397
                                        break;
 
45398
                                }
 
45399
                        }
 
45400
 
 
45401
                        /* advance to get one step of lookup */         
 
45402
                        duk__advance(comp_ctx);
 
45403
 
 
45404
                        /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
 
45405
                         * currently treats them always like ordinary identifiers (DUK_TOK_GET
 
45406
                         * and DUK_TOK_SET are unused).  They need to be detected based on the
 
45407
                         * identifier string content.
 
45408
                         */
 
45409
 
 
45410
                        is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
 
45411
                                  comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
 
45412
                        is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
 
45413
                                  comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
 
45414
                        if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
 
45415
                                /* getter/setter */
 
45416
                                int fnum;
 
45417
                                int reg_temp;
 
45418
 
 
45419
                                if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
 
45420
                                    comp_ctx->curr_token.t_nores == DUK_TOK_STRING) {
 
45421
                                        /* same handling for identifiers and strings */
 
45422
                                        DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
 
45423
                                        duk_push_hstring(ctx, comp_ctx->curr_token.str1);
 
45424
                                } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
 
45425
                                        duk_push_number(ctx, comp_ctx->curr_token.num);
 
45426
                                        duk_to_string(ctx, -1);
 
45427
                                } else {
 
45428
                                        goto syntax_error;
 
45429
                                }
 
45430
 
 
45431
                                DUK_ASSERT(duk_is_string(ctx, -1));
 
45432
                                if (duk__nud_object_literal_key_check(comp_ctx,
 
45433
                                                                      (is_get ? DUK__OBJ_LIT_KEY_GET : DUK__OBJ_LIT_KEY_SET))) {
 
45434
                                        goto syntax_error;
 
45435
                                }
 
45436
                                reg_key = duk__getconst(comp_ctx);
 
45437
 
 
45438
                                if (num_pairs > 0) {
 
45439
                                        /* - A is a source register (it's not a write target, but used
 
45440
                                         *   to identify the target object) but can be shuffled.
 
45441
                                         * - B cannot be shuffled normally because it identifies a range
 
45442
                                         *   of registers, the emitter has special handling for this.
 
45443
                                         * - C is a non-register number and cannot be shuffled, but
 
45444
                                         *   never needs to be.
 
45445
                                         */
 
45446
                                        duk__emit_a_b_c(comp_ctx,
 
45447
                                                        DUK_OP_MPUTOBJ |
 
45448
                                                            DUK__EMIT_FLAG_NO_SHUFFLE_C |
 
45449
                                                            DUK__EMIT_FLAG_A_IS_SOURCE,
 
45450
                                                        reg_obj,
 
45451
                                                        temp_start,
 
45452
                                                        num_pairs);
 
45453
                                        num_pairs = 0;
 
45454
                                        DUK__SETTEMP(comp_ctx, temp_start);
 
45455
                                }
 
45456
 
 
45457
                                /* curr_token = get/set name */
 
45458
                                fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
 
45459
 
 
45460
                                DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
 
45461
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45462
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_temp, reg_key);
 
45463
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45464
                                duk__emit_a_bc(comp_ctx, DUK_OP_CLOSURE, reg_temp, fnum);
 
45465
 
 
45466
                                /* Slot C is used in a non-standard fashion (range of regs),
 
45467
                                 * emitter code has special handling for it.
 
45468
                                 */
 
45469
                                duk__emit_extraop_b_c(comp_ctx,
 
45470
                                                      (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
 
45471
                                                      reg_obj,
 
45472
                                                      temp_start);   /* temp_start+0 = key, temp_start+1 = closure */
 
45473
 
 
45474
                                DUK__SETTEMP(comp_ctx, temp_start);
 
45475
                        } else {
 
45476
                                /* normal key/value */
 
45477
                                if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
 
45478
                                    comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
 
45479
                                        /* same handling for identifiers and strings */
 
45480
                                        DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
 
45481
                                        duk_push_hstring(ctx, comp_ctx->prev_token.str1);
 
45482
                                } else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
 
45483
                                        duk_push_number(ctx, comp_ctx->prev_token.num);
 
45484
                                        duk_to_string(ctx, -1);
 
45485
                                } else {
 
45486
                                        goto syntax_error;
 
45487
                                }
 
45488
 
 
45489
                                DUK_ASSERT(duk_is_string(ctx, -1));
 
45490
                                if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
 
45491
                                        goto syntax_error;
 
45492
                                }
 
45493
                                reg_key = duk__getconst(comp_ctx);
 
45494
 
 
45495
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45496
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_temp, reg_key);
 
45497
                                duk__advance_expect(comp_ctx, DUK_TOK_COLON);
 
45498
 
 
45499
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);  /* alloc temp just in case, to update max temp */
 
45500
                                DUK__SETTEMP(comp_ctx, reg_temp);
 
45501
                                duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
 
45502
                                DUK__SETTEMP(comp_ctx, reg_temp + 1);
 
45503
 
 
45504
                                num_pairs++;
 
45505
                        }
 
45506
                }
 
45507
 
 
45508
                if (num_pairs > 0) {
 
45509
                        /* See MPUTOBJ comments above. */
 
45510
                        duk__emit_a_b_c(comp_ctx,
 
45511
                                        DUK_OP_MPUTOBJ |
 
45512
                                            DUK__EMIT_FLAG_NO_SHUFFLE_C |
 
45513
                                            DUK__EMIT_FLAG_A_IS_SOURCE,
 
45514
                                        reg_obj,
 
45515
                                        temp_start,
 
45516
                                        num_pairs);
 
45517
#if 0  /* these are not necessary, as they're done at the top of the loop */
 
45518
                        num_pairs = 0;
 
45519
                        DUK__SETTEMP(comp_ctx, temp_start);
 
45520
#endif
 
45521
                }
 
45522
        }
 
45523
 
 
45524
        DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
 
45525
        duk__advance(comp_ctx);
 
45526
 
 
45527
        DUK__SETTEMP(comp_ctx, temp_start);
 
45528
 
 
45529
        res->t = DUK_IVAL_PLAIN;
 
45530
        res->x1.t = DUK_ISPEC_REGCONST;
 
45531
        res->x1.regconst = reg_obj;
 
45532
 
 
45533
        DUK_DDDPRINT("final tracking object: %!T", duk_get_tval(ctx, -1));
 
45534
        duk_pop(ctx);
 
45535
        return;
 
45536
 
 
45537
 syntax_error:
 
45538
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid object literal");
 
45539
}
 
45540
 
 
45541
/* Parse argument list.  Arguments are written to temps starting from
 
45542
 * "next temp".  Returns number of arguments parsed.  Expects left paren
 
45543
 * to be already eaten, and eats the right paren before returning.
 
45544
 */
 
45545
static int duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
45546
        int nargs = 0;
 
45547
        int tr;
 
45548
 
 
45549
        /* Note: expect that caller has already eaten the left paren */
 
45550
 
 
45551
        DUK_DDDPRINT("start parsing arguments, prev_token.t=%d, curr_token.t=%d",
 
45552
                     comp_ctx->prev_token.t, comp_ctx->curr_token.t);
 
45553
 
 
45554
        for (;;) {
 
45555
                if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
 
45556
                        break;
 
45557
                }
 
45558
                if (nargs > 0) {
 
45559
                        duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
 
45560
                }
 
45561
 
 
45562
                /* We want the argument expression value to go to "next temp"
 
45563
                 * without additional moves.  That should almost always be the
 
45564
                 * case, but we double check after expression parsing.
 
45565
                 *
 
45566
                 * This is not the cleanest possible approach.
 
45567
                 */
 
45568
 
 
45569
                tr = DUK__ALLOCTEMP(comp_ctx);  /* bump up "allocated" reg count, just in case */
 
45570
                DUK__SETTEMP(comp_ctx, tr);
 
45571
 
 
45572
                /* binding power must be high enough to NOT allow comma expressions directly */
 
45573
                duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, tr);  /* always allow 'in', coerce to 'tr' just in case */
 
45574
 
 
45575
                DUK__SETTEMP(comp_ctx, tr + 1);
 
45576
                nargs++;
 
45577
 
 
45578
                DUK_DDDPRINT("argument #%d written into reg %d", nargs, tr);
 
45579
        }
 
45580
 
 
45581
        /* eat the right paren */
 
45582
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
45583
 
 
45584
        DUK_DDDPRINT("end parsing arguments");
 
45585
 
 
45586
        return nargs;
 
45587
}
 
45588
 
 
45589
static int duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
 
45590
        /* empty expressions can be detected conveniently with nud/led counts */
 
45591
        return (comp_ctx->curr_func.nud_count == 0) &&
 
45592
               (comp_ctx->curr_func.led_count == 0);
 
45593
}
 
45594
 
 
45595
static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
45596
        duk_hthread *thr = comp_ctx->thr;
 
45597
        duk_context *ctx = (duk_context *) thr;
 
45598
        duk_token *tk;
 
45599
        int temp_at_entry;
 
45600
        int tok;
 
45601
        duk_uint32_t args;      /* temp variable to pass constants to shared code */
 
45602
 
 
45603
        /*
 
45604
         *  ctx->prev_token     token to process with duk__expr_nud()
 
45605
         *  ctx->curr_token     updated by caller
 
45606
         *
 
45607
         *  Note: the token in the switch below has already been eaten.
 
45608
         */
 
45609
 
 
45610
        temp_at_entry = DUK__GETTEMP(comp_ctx);
 
45611
 
 
45612
        comp_ctx->curr_func.nud_count++;
 
45613
 
 
45614
        tk = &comp_ctx->prev_token;
 
45615
        tok = tk->t;
 
45616
        res->t = DUK_IVAL_NONE;
 
45617
 
 
45618
        DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%d, allow_in=%d, paren_level=%d",
 
45619
                     tk->t, comp_ctx->curr_func.allow_in, comp_ctx->curr_func.paren_level);
 
45620
 
 
45621
        switch (tok) {
 
45622
 
 
45623
        /* PRIMARY EXPRESSIONS */
 
45624
 
 
45625
        case DUK_TOK_THIS: {
 
45626
                int reg_temp;
 
45627
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45628
                duk__emit_extraop_b(comp_ctx,
 
45629
                                    DUK_EXTRAOP_LDTHIS | DUK__EMIT_FLAG_B_IS_TARGET,
 
45630
                                    reg_temp);
 
45631
                res->t = DUK_IVAL_PLAIN;
 
45632
                res->x1.t = DUK_ISPEC_REGCONST;
 
45633
                res->x1.regconst = reg_temp;
 
45634
                return;
 
45635
        }
 
45636
        case DUK_TOK_IDENTIFIER: {
 
45637
                res->t = DUK_IVAL_VAR;
 
45638
                res->x1.t = DUK_ISPEC_VALUE;
 
45639
                duk_push_hstring(ctx, tk->str1);
 
45640
                duk_replace(ctx, res->x1.valstack_idx);
 
45641
                return;
 
45642
        }
 
45643
        case DUK_TOK_NULL: {
 
45644
                duk_push_null(ctx);
 
45645
                goto plain_value;
 
45646
        }
 
45647
        case DUK_TOK_TRUE: {
 
45648
                duk_push_true(ctx);
 
45649
                goto plain_value;
 
45650
        }
 
45651
        case DUK_TOK_FALSE: {
 
45652
                duk_push_false(ctx);
 
45653
                goto plain_value;
 
45654
        }
 
45655
        case DUK_TOK_NUMBER: {
 
45656
                duk_push_number(ctx, tk->num);
 
45657
                goto plain_value;
 
45658
        }
 
45659
        case DUK_TOK_STRING: {
 
45660
                DUK_ASSERT(tk->str1 != NULL);
 
45661
                duk_push_hstring(ctx, tk->str1);
 
45662
                goto plain_value;
 
45663
        }
 
45664
        case DUK_TOK_REGEXP: {
 
45665
#ifdef DUK_USE_REGEXP_SUPPORT
 
45666
                int reg_temp;
 
45667
                int reg_re_bytecode;  /* const */
 
45668
                int reg_re_source;    /* const */
 
45669
 
 
45670
                DUK_ASSERT(tk->str1 != NULL);
 
45671
                DUK_ASSERT(tk->str2 != NULL);
 
45672
 
 
45673
                DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O", tk->str1, tk->str2);
 
45674
 
 
45675
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45676
                duk_push_hstring(ctx, tk->str1);
 
45677
                duk_push_hstring(ctx, tk->str2);
 
45678
 
 
45679
                /* [ ... pattern flags ] */
 
45680
 
 
45681
                duk_regexp_compile(thr);
 
45682
 
 
45683
                /* [ ... escaped_source bytecode ] */
 
45684
 
 
45685
                reg_re_bytecode = duk__getconst(comp_ctx);
 
45686
                reg_re_source = duk__getconst(comp_ctx);
 
45687
 
 
45688
                duk__emit_a_b_c(comp_ctx,
 
45689
                                DUK_OP_REGEXP,
 
45690
                                reg_temp /*a*/,
 
45691
                                reg_re_bytecode /*b*/,
 
45692
                                reg_re_source /*c*/);
 
45693
 
 
45694
                res->t = DUK_IVAL_PLAIN;
 
45695
                res->x1.t = DUK_ISPEC_REGCONST;
 
45696
                res->x1.regconst = reg_temp;
 
45697
                return;
 
45698
#else  /* DUK_USE_REGEXP_SUPPORT */
 
45699
                goto syntax_error;
 
45700
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
45701
        }
 
45702
        case DUK_TOK_LBRACKET: {
 
45703
                DUK_DDDPRINT("parsing array literal");
 
45704
                duk__nud_array_literal(comp_ctx, res);
 
45705
                return;
 
45706
        }
 
45707
        case DUK_TOK_LCURLY: {
 
45708
                DUK_DDDPRINT("parsing object literal");
 
45709
                duk__nud_object_literal(comp_ctx, res);
 
45710
                return;
 
45711
        }
 
45712
        case DUK_TOK_LPAREN: {
 
45713
                int prev_allow_in;
 
45714
 
 
45715
                comp_ctx->curr_func.paren_level++;
 
45716
                prev_allow_in = comp_ctx->curr_func.allow_in;
 
45717
                comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
 
45718
 
 
45719
                duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression, terminates at a ')' */
 
45720
 
 
45721
                duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
45722
                comp_ctx->curr_func.allow_in = prev_allow_in;
 
45723
                comp_ctx->curr_func.paren_level--;
 
45724
                return;
 
45725
        }
 
45726
 
 
45727
        /* MEMBER/NEW/CALL EXPRESSIONS */
 
45728
 
 
45729
        case DUK_TOK_NEW: {
 
45730
                /*
 
45731
                 *  Parsing an expression starting with 'new' is tricky because
 
45732
                 *  there are multiple possible productions deriving from
 
45733
                 *  LeftHandSideExpression which begin with 'new'.
 
45734
                 *
 
45735
                 *  We currently resort to one-token lookahead to distinguish the
 
45736
                 *  cases.  Hopefully this is correct.  The binding power must be
 
45737
                 *  such that parsing ends at an LPAREN (CallExpression) but not at
 
45738
                 *  a PERIOD or LBRACKET (MemberExpression).
 
45739
                 *
 
45740
                 *  See doc/compiler.txt for discussion on the parsing approach,
 
45741
                 *  and testcases/test-dev-new.js for a bunch of documented tests.
 
45742
                 */
 
45743
 
 
45744
                int reg_target;
 
45745
                int nargs;
 
45746
 
 
45747
                DUK_DDDPRINT("begin parsing new expression");
 
45748
 
 
45749
                reg_target = DUK__ALLOCTEMP(comp_ctx);
 
45750
                duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
 
45751
                DUK__SETTEMP(comp_ctx, reg_target + 1);
 
45752
 
 
45753
                if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
 
45754
                        /* 'new' MemberExpression Arguments */
 
45755
                        DUK_DDDPRINT("new expression has argument list");
 
45756
                        duk__advance(comp_ctx);
 
45757
                        nargs = duk__parse_arguments(comp_ctx, res);  /* parse args starting from "next temp", reg_target + 1 */
 
45758
                        /* right paren eaten */
 
45759
                } else {
 
45760
                        /* 'new' MemberExpression */
 
45761
                        DUK_DDDPRINT("new expression has no argument list");
 
45762
                        nargs = 0;
 
45763
                }
 
45764
 
 
45765
                /* Opcode slot C is used in a non-standard way, so shuffling
 
45766
                 * is not allowed.
 
45767
                 */
 
45768
                duk__emit_a_b_c(comp_ctx,
 
45769
                              DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
 
45770
                              0 /*unused*/,
 
45771
                              reg_target /*target*/,
 
45772
                              nargs /*num_args*/);
 
45773
 
 
45774
                DUK_DDDPRINT("end parsing new expression");
 
45775
 
 
45776
                res->t = DUK_IVAL_PLAIN;
 
45777
                res->x1.t = DUK_ISPEC_REGCONST;
 
45778
                res->x1.regconst = reg_target;
 
45779
                return;
 
45780
        }
 
45781
 
 
45782
        /* FUNCTION EXPRESSIONS */
 
45783
 
 
45784
        case DUK_TOK_FUNCTION: {
 
45785
                /* Function expression.  Note that any statement beginning with 'function'
 
45786
                 * is handled by the statement parser as a function declaration, or a
 
45787
                 * non-standard function expression/statement (or a SyntaxError).  We only
 
45788
                 * handle actual function expressions (occurring inside an expression) here.
 
45789
                 *
 
45790
                 * O(depth^2) parse count for inner functions is handled by recording a
 
45791
                 * lexer offset on the first compilation pass, so that the function can
 
45792
                 * be efficiently skipped on the second pass.  This is encapsulated into
 
45793
                 * duk__parse_func_like_fnum().
 
45794
                 */
 
45795
 
 
45796
                int reg_temp;
 
45797
                int fnum;
 
45798
 
 
45799
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45800
 
 
45801
                /* curr_token follows 'function' */
 
45802
                fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 0 /*is_setget*/);
 
45803
                DUK_DDDPRINT("parsed inner function -> fnum %d", fnum);
 
45804
 
 
45805
                duk__emit_a_bc(comp_ctx, DUK_OP_CLOSURE, reg_temp /*a*/, fnum /*bc*/);
 
45806
 
 
45807
                res->t = DUK_IVAL_PLAIN;
 
45808
                res->x1.t = DUK_ISPEC_REGCONST;
 
45809
                res->x1.regconst = reg_temp;
 
45810
                return;
 
45811
        }
 
45812
 
 
45813
        /* UNARY EXPRESSIONS */
 
45814
 
 
45815
        case DUK_TOK_DELETE: {
 
45816
                /* Delete semantics are a bit tricky.  The description in E5 specification
 
45817
                 * is kind of confusing, because it distinguishes between resolvability of
 
45818
                 * a reference (which is only known at runtime) seemingly at compile time
 
45819
                 * (= SyntaxError throwing).
 
45820
                 */
 
45821
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45822
                if (res->t == DUK_IVAL_VAR) {
 
45823
                        /* not allowed in strict mode, regardless of whether resolves;
 
45824
                         * in non-strict mode DELVAR handles both non-resolving and
 
45825
                         * resolving cases (the specification description is a bit confusing).
 
45826
                         */
 
45827
 
 
45828
                        int reg_temp;
 
45829
                        int reg_varname;
 
45830
                        int reg_varbind;
 
45831
 
 
45832
                        if (comp_ctx->curr_func.is_strict) {
 
45833
                                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "cannot delete identifier");
 
45834
                        }
 
45835
 
 
45836
                        DUK__SETTEMP(comp_ctx, temp_at_entry);
 
45837
                        reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45838
 
 
45839
                        duk_dup(ctx, res->x1.valstack_idx);
 
45840
                        if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
45841
                                /* register bound variables are non-configurable -> always false */
 
45842
                                duk__emit_extraop_bc(comp_ctx,
 
45843
                                                     DUK_EXTRAOP_LDFALSE, reg_temp);
 
45844
                        } else {
 
45845
                                duk_dup(ctx, res->x1.valstack_idx);
 
45846
                                reg_varname = duk__getconst(comp_ctx);
 
45847
                                duk__emit_a_b(comp_ctx, DUK_OP_DELVAR, reg_temp, reg_varname);
 
45848
                        }
 
45849
                        res->t = DUK_IVAL_PLAIN;
 
45850
                        res->x1.t = DUK_ISPEC_REGCONST;
 
45851
                        res->x1.regconst = reg_temp;
 
45852
                } else if (res->t == DUK_IVAL_PROP) {
 
45853
                        int reg_temp;
 
45854
                        int reg_obj;
 
45855
                        int reg_key;
 
45856
 
 
45857
                        DUK__SETTEMP(comp_ctx, temp_at_entry);
 
45858
                        reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
45859
                        reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
 
45860
                        reg_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
45861
                        duk__emit_a_b_c(comp_ctx, DUK_OP_DELPROP, reg_temp, reg_obj, reg_key);
 
45862
 
 
45863
                        res->t = DUK_IVAL_PLAIN;
 
45864
                        res->x1.t = DUK_ISPEC_REGCONST;
 
45865
                        res->x1.regconst = reg_temp;
 
45866
                } else {
 
45867
                        /* non-Reference deletion is always 'true', even in strict mode */
 
45868
                        duk_push_true(ctx);
 
45869
                        goto plain_value;
 
45870
                }
 
45871
                return;
 
45872
        }
 
45873
        case DUK_TOK_VOID: {
 
45874
                duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45875
                duk_push_undefined(ctx);
 
45876
                goto plain_value;
 
45877
        }
 
45878
        case DUK_TOK_TYPEOF: {
 
45879
                /* 'typeof' must handle unresolvable references without throwing
 
45880
                 * a ReferenceError (E5 Section 11.4.3).  Register mapped values
 
45881
                 * will never be unresolvable so special handling is only required
 
45882
                 * when an identifier is a "slow path" one.
 
45883
                 */
 
45884
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45885
 
 
45886
                if (res->t == DUK_IVAL_VAR) {
 
45887
                        int reg_varbind;
 
45888
                        int reg_varname;
 
45889
                        int tr;
 
45890
 
 
45891
                        duk_dup(ctx, res->x1.valstack_idx);
 
45892
                        if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
45893
                                DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
 
45894
                                             "at compile time, need to use special run-time handling");
 
45895
                                tr = DUK__ALLOCTEMP(comp_ctx);
 
45896
                                duk__emit_extraop_b_c(comp_ctx,
 
45897
                                                      DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET,
 
45898
                                                      tr,
 
45899
                                                      reg_varname);
 
45900
                                res->t = DUK_IVAL_PLAIN;
 
45901
                                res->x1.t = DUK_ISPEC_REGCONST;
 
45902
                                res->x1.regconst = tr;
 
45903
                                return;
 
45904
                        }
 
45905
                }
 
45906
 
 
45907
                args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
 
45908
                goto unary_extraop;
 
45909
        }
 
45910
        case DUK_TOK_INCREMENT: {
 
45911
                args = (DUK_EXTRAOP_INC << 8) + 0;
 
45912
                goto preincdec_extraop;
 
45913
        }
 
45914
        case DUK_TOK_DECREMENT: {
 
45915
                args = (DUK_EXTRAOP_DEC << 8) + 0;
 
45916
                goto preincdec_extraop;
 
45917
        }
 
45918
        case DUK_TOK_ADD: {
 
45919
                /* unary plus */
 
45920
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45921
                if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
 
45922
                    duk_is_number(ctx, res->x1.valstack_idx)) {
 
45923
                        /* unary plus of a number is identity */
 
45924
                        ;
 
45925
                } else {
 
45926
                        args = (DUK_EXTRAOP_UNP << 8) + 0;
 
45927
                        goto unary_extraop;
 
45928
                }
 
45929
                return;
 
45930
        }
 
45931
        case DUK_TOK_SUB: {
 
45932
                /* unary minus */
 
45933
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45934
                if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
 
45935
                    duk_is_number(ctx, res->x1.valstack_idx)) {
 
45936
                        /* this optimization is important to handle negative literals (which are not directly
 
45937
                         * provided by the lexical grammar
 
45938
                         */
 
45939
                        duk_tval *tv_num = duk_get_tval(ctx, res->x1.valstack_idx);
 
45940
                        double d;
 
45941
 
 
45942
                        DUK_ASSERT(tv_num != NULL);
 
45943
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
 
45944
                        d = DUK_TVAL_GET_NUMBER(tv_num);
 
45945
                        DUK_TVAL_SET_NUMBER(tv_num, -d);  /* FIXME: OK for NaN, Infinity?  NaN normalization? */
 
45946
                } else {
 
45947
                        args = (DUK_EXTRAOP_UNM << 8) + 0;
 
45948
                        goto unary_extraop;
 
45949
                }
 
45950
                return;
 
45951
        }
 
45952
        case DUK_TOK_BNOT: {
 
45953
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45954
                args = (DUK_OP_BNOT << 8) + 0;
 
45955
                goto unary;
 
45956
        }
 
45957
        case DUK_TOK_LNOT: {
 
45958
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
45959
                args = (DUK_OP_LNOT << 8) + 0;
 
45960
                goto unary;
 
45961
        }
 
45962
 
 
45963
        }
 
45964
 
 
45965
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "unexpected token to duk__expr_nud(): %d", tok);
 
45966
        return;
 
45967
 
 
45968
 unary:
 
45969
        {
 
45970
                /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
 
45971
                 * is a reg-mapped variable works correctly (does not mutate the variable register).
 
45972
                 */
 
45973
 
 
45974
                int tr;
 
45975
                tr = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
 
45976
                duk__emit_a_b(comp_ctx, args >> 8, tr, tr);
 
45977
                res->t = DUK_IVAL_PLAIN;
 
45978
                res->x1.t = DUK_ISPEC_REGCONST;
 
45979
                res->x1.regconst = tr;
 
45980
                return;
 
45981
        }
 
45982
 
 
45983
 unary_extraop:
 
45984
        {
 
45985
                /* FIXME: refactor into unary2: above? */
 
45986
                int tr;
 
45987
                tr = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
 
45988
                duk__emit_extraop_b_c(comp_ctx,
 
45989
                                      (args >> 8) | DUK__EMIT_FLAG_B_IS_TARGET,
 
45990
                                      tr,
 
45991
                                      tr);
 
45992
                res->t = DUK_IVAL_PLAIN;
 
45993
                res->x1.t = DUK_ISPEC_REGCONST;
 
45994
                res->x1.regconst = tr;
 
45995
                return;
 
45996
        }
 
45997
 
 
45998
 preincdec_extraop:
 
45999
        {
 
46000
                /* preincrement and predecrement */
 
46001
                int reg_res;
 
46002
                int args_op = args >> 8;
 
46003
 
 
46004
                reg_res = DUK__ALLOCTEMP(comp_ctx);
 
46005
 
 
46006
                duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
 
46007
                if (res->t == DUK_IVAL_VAR) {
 
46008
                        duk_hstring *h_varname;
 
46009
                        int reg_varbind;
 
46010
                        int reg_varname;
 
46011
 
 
46012
                        h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
 
46013
                        DUK_ASSERT(h_varname != NULL);
 
46014
 
 
46015
                        if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
 
46016
                                goto syntax_error;
 
46017
                        }
 
46018
 
 
46019
                        duk_dup(ctx, res->x1.valstack_idx);
 
46020
                        if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
46021
                                duk__emit_extraop_b_c(comp_ctx,
 
46022
                                                      args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46023
                                                      reg_varbind,
 
46024
                                                      reg_varbind);
 
46025
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_res, reg_varbind);
 
46026
                        } else {
 
46027
                                duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, reg_res, reg_varname);
 
46028
                                duk__emit_extraop_b_c(comp_ctx,
 
46029
                                                      args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46030
                                                      reg_res,
 
46031
                                                      reg_res);
 
46032
                                duk__emit_a_bc(comp_ctx,
 
46033
                                               DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
46034
                                               reg_res,
 
46035
                                               reg_varname);
 
46036
                        }
 
46037
 
 
46038
                        DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%d, reg_varname=%d",
 
46039
                                     h_varname, reg_varbind, reg_varname);
 
46040
                } else if (res->t == DUK_IVAL_PROP) {
 
46041
                        int reg_obj;  /* allocate to reg only (not const) */
 
46042
                        int reg_key;
 
46043
                        reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
 
46044
                        reg_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
46045
                        duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_res, reg_obj, reg_key);
 
46046
                        duk__emit_extraop_b_c(comp_ctx,
 
46047
                                              args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46048
                                              reg_res,
 
46049
                                              reg_res);
 
46050
                        duk__emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_res);
 
46051
                } else {
 
46052
                        /* Technically return value is not needed because INVLHS will
 
46053
                         * unconditially throw a ReferenceError.  Coercion is necessary
 
46054
                         * for proper semantics (consider ToNumber() called for an object).
 
46055
                         */
 
46056
                        duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
 
46057
                        duk__emit_extraop_b_c(comp_ctx,
 
46058
                                              DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET,
 
46059
                                              reg_res,
 
46060
                                              reg_res);  /* for side effects */
 
46061
                        duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS);
 
46062
                }
 
46063
                res->t = DUK_IVAL_PLAIN;
 
46064
                res->x1.t = DUK_ISPEC_REGCONST;
 
46065
                res->x1.regconst = reg_res;
 
46066
                DUK__SETTEMP(comp_ctx, reg_res + 1);
 
46067
                return;
 
46068
        }
 
46069
 
 
46070
 plain_value:
 
46071
        {
 
46072
                /* Stack top contains plain value */
 
46073
                res->t = DUK_IVAL_PLAIN;
 
46074
                res->x1.t = DUK_ISPEC_VALUE;
 
46075
                duk_replace(ctx, res->x1.valstack_idx);
 
46076
                return;
 
46077
        }
 
46078
 
 
46079
 syntax_error:
 
46080
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid expression");
 
46081
}
 
46082
 
 
46083
/* FIXME: add flag to indicate whether caller cares about return value; this
 
46084
 * affects e.g. handling of assignment expressions.  This change needs API
 
46085
 * changes elsewhere too.
 
46086
 */
 
46087
static void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
 
46088
        duk_hthread *thr = comp_ctx->thr;
 
46089
        duk_context *ctx = (duk_context *) thr;
 
46090
        duk_token *tk;
 
46091
        int tok;
 
46092
        duk_uint32_t args;      /* temp variable to pass constants and flags to shared code */
 
46093
 
 
46094
        /*
 
46095
         *  ctx->prev_token     token to process with duk__expr_led()
 
46096
         *  ctx->curr_token     updated by caller
 
46097
         */
 
46098
 
 
46099
        comp_ctx->curr_func.led_count++;
 
46100
 
 
46101
        /* The token in the switch has already been eaten here */
 
46102
        tk = &comp_ctx->prev_token;
 
46103
        tok = tk->t;
 
46104
 
 
46105
        DUK_DDDPRINT("duk__expr_led(), prev_token.t=%d, allow_in=%d, paren_level=%d",
 
46106
                     tk->t, comp_ctx->curr_func.allow_in, comp_ctx->curr_func.paren_level);
 
46107
 
 
46108
        /* FIXME: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
 
46109
 
 
46110
        switch (tok) {
 
46111
 
 
46112
        /* PRIMARY EXPRESSIONS */
 
46113
 
 
46114
        case DUK_TOK_PERIOD: {
 
46115
                /* FIXME: this now coerces an identifier into a GETVAR to a temp, which
 
46116
                 * causes an extra LDREG in call setup.  It's sufficient to coerce to a
 
46117
                 * unary ivalue?
 
46118
                 */
 
46119
                duk__ivalue_toplain(comp_ctx, left);
 
46120
 
 
46121
                /* NB: must accept reserved words as property name */
 
46122
                if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
 
46123
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "expecting identifier name");
 
46124
                }
 
46125
 
 
46126
                /* FIXME: use "dup+replace" primitive */
 
46127
                res->t = DUK_IVAL_PROP;
 
46128
                duk__copy_ispec(comp_ctx, &left->x1, &res->x1);  /* left.x1 -> res.x1 */
 
46129
                DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
 
46130
                duk_push_hstring(ctx, comp_ctx->curr_token.str1);
 
46131
                duk_replace(ctx, res->x2.valstack_idx);
 
46132
                res->x2.t = DUK_ISPEC_VALUE;
 
46133
 
 
46134
                /* special RegExp literal handling after IdentifierName */
 
46135
                comp_ctx->curr_func.reject_regexp_in_adv = 1;
 
46136
 
 
46137
                duk__advance(comp_ctx);
 
46138
                return;
 
46139
        }
 
46140
        case DUK_TOK_LBRACKET: {
 
46141
                /* FIXME: optimize temp reg use */
 
46142
                /* FIXME: similar coercion issue as in DUK_TOK_PERIOD */
 
46143
 
 
46144
                duk__ivalue_toplain(comp_ctx, left);
 
46145
 
 
46146
                duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression, ']' terminates */
 
46147
 
 
46148
                duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
 
46149
 
 
46150
                /* FIXME: coerce to regs? it might be better for enumeration use, where the
 
46151
                 * same PROP ivalue is used multiple times.  Or perhaps coerce PROP further
 
46152
                 * there?
 
46153
                 */
 
46154
 
 
46155
                res->t = DUK_IVAL_PROP;
 
46156
                duk__copy_ispec(comp_ctx, &res->x1, &res->x2);   /* res.x1 -> res.x2 */
 
46157
                duk__copy_ispec(comp_ctx, &left->x1, &res->x1);  /* left.x1 -> res.x1 */
 
46158
                return;
 
46159
        }
 
46160
        case DUK_TOK_LPAREN: {
 
46161
                /* function call */
 
46162
                int reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
 
46163
                int nargs;
 
46164
                int call_flags = 0;
 
46165
 
 
46166
                /*
 
46167
                 *  FIXME: attempt to get the call result to "next temp" whenever
 
46168
                 *  possible to avoid unnecessary register shuffles.
 
46169
                 *
 
46170
                 *  FIXME: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
 
46171
                 *  if the call target is a temporary register and at the top of the temp reg "stack".
 
46172
                 */
 
46173
 
 
46174
                /*
 
46175
                 *  Setup call: target and 'this' binding.  Three cases:
 
46176
                 *
 
46177
                 *    1. Identifier base (e.g. "foo()")
 
46178
                 *    2. Property base (e.g. "foo.bar()")
 
46179
                 *    3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
 
46180
                 */
 
46181
 
 
46182
                if (left->t == DUK_IVAL_VAR) {
 
46183
                        duk_hstring *h_varname;
 
46184
                        int reg_varname;
 
46185
                        int reg_varbind;
 
46186
 
 
46187
                        DUK_DDDPRINT("function call with identifier base");
 
46188
 
 
46189
                        h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
 
46190
                        DUK_ASSERT(h_varname != NULL);
 
46191
                        if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
 
46192
                                /* Potential direct eval call detected, flag the CALL
 
46193
                                 * so that a run-time "direct eval" check is made and
 
46194
                                 * special behavior may be triggered.  Note that this
 
46195
                                 * does not prevent 'eval' from being register bound.
 
46196
                                 */
 
46197
                                DUK_DDDPRINT("function call with identifier 'eval' "
 
46198
                                             "-> enabling EVALCALL flag, marking function "
 
46199
                                             "as may_direct_eval");
 
46200
                                call_flags |= DUK_BC_CALL_FLAG_EVALCALL;
 
46201
 
 
46202
                                comp_ctx->curr_func.may_direct_eval = 1;
 
46203
                        }
 
46204
 
 
46205
                        duk_dup(ctx, left->x1.valstack_idx);
 
46206
                        if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
46207
                                duk__emit_a_b(comp_ctx,
 
46208
                                              DUK_OP_CSREG,
 
46209
                                              reg_cs + 0,
 
46210
                                              reg_varbind);
 
46211
                        } else {
 
46212
                                duk__emit_a_b(comp_ctx,
 
46213
                                              DUK_OP_CSVAR,
 
46214
                                              reg_cs + 0,
 
46215
                                              reg_varname);
 
46216
                        }
 
46217
                } else if (left->t == DUK_IVAL_PROP) {
 
46218
                        DUK_DDDPRINT("function call with property base");
 
46219
                        
 
46220
                        duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 0);  /* base */
 
46221
                        duk__ispec_toforcedreg(comp_ctx, &left->x2, reg_cs + 1);  /* key */
 
46222
                        duk__emit_a_b_c(comp_ctx,
 
46223
                                        DUK_OP_CSPROP,
 
46224
                                        reg_cs + 0,
 
46225
                                        reg_cs + 0,
 
46226
                                        reg_cs + 1);  /* in-place setup */
 
46227
                } else {
 
46228
                        DUK_DDDPRINT("function call with register base");
 
46229
 
 
46230
                        duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
 
46231
                        duk__emit_a_b(comp_ctx,
 
46232
                                      DUK_OP_CSREG,
 
46233
                                      reg_cs + 0,
 
46234
                                      reg_cs + 0);  /* in-place setup */
 
46235
                }
 
46236
 
 
46237
                DUK__SETTEMP(comp_ctx, reg_cs + 2);
 
46238
                nargs = duk__parse_arguments(comp_ctx, res);  /* parse args starting from "next temp" */
 
46239
 
 
46240
                /* Tailcalls are handled by back-patching the TAILCALL flag to the
 
46241
                 * already emitted instruction later (in return statement parser).
 
46242
                 * Since A and C have a special meaning here, they cannot be "shuffled".
 
46243
                 */
 
46244
 
 
46245
                duk__emit_a_b_c(comp_ctx,
 
46246
                                DUK_OP_CALL | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
 
46247
                                call_flags /*flags*/,
 
46248
                                reg_cs /*basereg*/,
 
46249
                                nargs /*numargs*/);
 
46250
                DUK__SETTEMP(comp_ctx, reg_cs + 1);    /* result in csreg */
 
46251
 
 
46252
                res->t = DUK_IVAL_PLAIN;
 
46253
                res->x1.t = DUK_ISPEC_REGCONST;
 
46254
                res->x1.regconst = reg_cs;
 
46255
                return;
 
46256
        }
 
46257
 
 
46258
        /* POSTFIX EXPRESSION */
 
46259
 
 
46260
        case DUK_TOK_INCREMENT: {
 
46261
                args = (DUK_EXTRAOP_INC << 8) + 0;
 
46262
                goto postincdec_extraop;
 
46263
        }
 
46264
        case DUK_TOK_DECREMENT: {
 
46265
                args = (DUK_EXTRAOP_DEC << 8) + 0;
 
46266
                goto postincdec_extraop;
 
46267
        }
 
46268
 
 
46269
        /* MULTIPLICATIVE EXPRESSION */
 
46270
 
 
46271
        case DUK_TOK_MUL: {
 
46272
                args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE;  /* UnaryExpression */
 
46273
                goto binary;
 
46274
        }
 
46275
        case DUK_TOK_DIV: {
 
46276
                args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE;  /* UnaryExpression */
 
46277
                goto binary;
 
46278
        }
 
46279
        case DUK_TOK_MOD: {
 
46280
                args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE;  /* UnaryExpression */
 
46281
                goto binary;
 
46282
        }
 
46283
 
 
46284
        /* ADDITIVE EXPRESSION */
 
46285
 
 
46286
        case DUK_TOK_ADD: {
 
46287
                args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE;  /* MultiplicativeExpression */
 
46288
                goto binary;
 
46289
        }
 
46290
        case DUK_TOK_SUB: {
 
46291
                args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE;  /* MultiplicativeExpression */
 
46292
                goto binary;
 
46293
        }
 
46294
 
 
46295
        /* SHIFT EXPRESSION */
 
46296
 
 
46297
        case DUK_TOK_ALSHIFT: {
 
46298
                /* << */
 
46299
                args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
 
46300
                goto binary;
 
46301
        }
 
46302
        case DUK_TOK_ARSHIFT: {
 
46303
                /* >> */
 
46304
                args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
 
46305
                goto binary;
 
46306
        }
 
46307
        case DUK_TOK_RSHIFT: {
 
46308
                /* >>> */
 
46309
                args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
 
46310
                goto binary;
 
46311
        }
 
46312
 
 
46313
        /* RELATIONAL EXPRESSION */
 
46314
 
 
46315
        case DUK_TOK_LT: {
 
46316
                /* < */
 
46317
                args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
 
46318
                goto binary;
 
46319
        }
 
46320
        case DUK_TOK_GT: {
 
46321
                args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
 
46322
                goto binary;
 
46323
        }
 
46324
        case DUK_TOK_LE: {
 
46325
                args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
 
46326
                goto binary;
 
46327
        }
 
46328
        case DUK_TOK_GE: {
 
46329
                args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
 
46330
                goto binary;
 
46331
        }
 
46332
        case DUK_TOK_INSTANCEOF: {
 
46333
                args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL;
 
46334
                goto binary;
 
46335
        }
 
46336
        case DUK_TOK_IN: {
 
46337
                args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL;
 
46338
                goto binary;
 
46339
        }
 
46340
 
 
46341
        /* EQUALITY EXPRESSION */
 
46342
 
 
46343
        case DUK_TOK_EQ: {
 
46344
                args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
 
46345
                goto binary;
 
46346
        }
 
46347
        case DUK_TOK_NEQ: {
 
46348
                args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
 
46349
                goto binary;
 
46350
        }
 
46351
        case DUK_TOK_SEQ: {
 
46352
                args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
 
46353
                goto binary;
 
46354
        }
 
46355
        case DUK_TOK_SNEQ: {
 
46356
                args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
 
46357
                goto binary;
 
46358
        }
 
46359
 
 
46360
        /* BITWISE EXPRESSIONS */
 
46361
 
 
46362
        case DUK_TOK_BAND: {
 
46363
                args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
 
46364
                goto binary;
 
46365
        }
 
46366
        case DUK_TOK_BXOR: {
 
46367
                args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
 
46368
                goto binary;
 
46369
        }
 
46370
        case DUK_TOK_BOR: {
 
46371
                args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
 
46372
                goto binary;
 
46373
        }
 
46374
 
 
46375
        /* LOGICAL EXPRESSIONS */
 
46376
 
 
46377
        case DUK_TOK_LAND: {
 
46378
                /* syntactically left-associative but parsed as right-associative */
 
46379
                args = (1 << 8) + DUK__BP_LAND - 1;
 
46380
                goto binary_logical;
 
46381
        }
 
46382
        case DUK_TOK_LOR: {
 
46383
                /* syntactically left-associative but parsed as right-associative */
 
46384
                args = (0 << 8) + DUK__BP_LOR - 1;
 
46385
                goto binary_logical;
 
46386
        }
 
46387
 
 
46388
        /* CONDITIONAL EXPRESSION */
 
46389
 
 
46390
        case DUK_TOK_QUESTION: {
 
46391
                /* FIXME: common reg allocation need is to reuse a sub-expression's temp reg,
 
46392
                 * but only if it really is a temp.  Nothing fancy here now.
 
46393
                 */
 
46394
                int reg_temp;
 
46395
                int pc_jump1;
 
46396
                int pc_jump2;
 
46397
 
 
46398
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46399
                duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
 
46400
                duk__emit_if_true_skip(comp_ctx, reg_temp);
 
46401
                pc_jump1 = duk__emit_jump_empty(comp_ctx);  /* jump to false */
 
46402
                duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);  /* AssignmentExpression */
 
46403
                duk__advance_expect(comp_ctx, DUK_TOK_COLON);
 
46404
                pc_jump2 = duk__emit_jump_empty(comp_ctx);  /* jump to end */
 
46405
                duk__patch_jump_here(comp_ctx, pc_jump1);
 
46406
                duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);  /* AssignmentExpression */
 
46407
                duk__patch_jump_here(comp_ctx, pc_jump2);
 
46408
 
 
46409
                DUK__SETTEMP(comp_ctx, reg_temp + 1);
 
46410
                res->t = DUK_IVAL_PLAIN;
 
46411
                res->x1.t = DUK_ISPEC_REGCONST;
 
46412
                res->x1.regconst = reg_temp;
 
46413
                return;
 
46414
        }
 
46415
 
 
46416
        /* ASSIGNMENT EXPRESSION */
 
46417
 
 
46418
        case DUK_TOK_EQUALSIGN: {
 
46419
                /*
 
46420
                 *  Assignments are right associative, allows e.g.
 
46421
                 *    a = 5;
 
46422
                 *    a += b = 9;   // same as a += (b = 9)
 
46423
                 *  -> expression value 14, a = 14, b = 9
 
46424
                 *
 
46425
                 *  Right associativiness is reflected in the BP for recursion,
 
46426
                 *  "-1" ensures assignment operations are allowed.
 
46427
                 *
 
46428
                 *  FIXME: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
 
46429
                 */
 
46430
                args = (DUK_OP_INVALID << 8) + DUK__BP_ASSIGNMENT - 1;   /* DUK_OP_INVALID marks a 'plain' assignment */
 
46431
                goto assign;
 
46432
        }
 
46433
        case DUK_TOK_ADD_EQ: {
 
46434
                /* right associative */
 
46435
                args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
 
46436
                goto assign;
 
46437
        }
 
46438
        case DUK_TOK_SUB_EQ: {
 
46439
                /* right associative */
 
46440
                args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
 
46441
                goto assign;
 
46442
        }
 
46443
        case DUK_TOK_MUL_EQ: {
 
46444
                /* right associative */
 
46445
                args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
 
46446
                goto assign;
 
46447
        }
 
46448
        case DUK_TOK_DIV_EQ: {
 
46449
                /* right associative */
 
46450
                args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
 
46451
                goto assign;
 
46452
        }
 
46453
        case DUK_TOK_MOD_EQ: {
 
46454
                /* right associative */
 
46455
                args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
 
46456
                goto assign;
 
46457
        }
 
46458
        case DUK_TOK_ALSHIFT_EQ: {
 
46459
                /* right associative */
 
46460
                args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
 
46461
                goto assign;
 
46462
        }
 
46463
        case DUK_TOK_ARSHIFT_EQ: {
 
46464
                /* right associative */
 
46465
                args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
 
46466
                goto assign;
 
46467
        }
 
46468
        case DUK_TOK_RSHIFT_EQ: {
 
46469
                /* right associative */
 
46470
                args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
 
46471
                goto assign;
 
46472
        }
 
46473
        case DUK_TOK_BAND_EQ: {
 
46474
                /* right associative */
 
46475
                args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
 
46476
                goto assign;
 
46477
        }
 
46478
        case DUK_TOK_BOR_EQ: {
 
46479
                /* right associative */
 
46480
                args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
 
46481
                goto assign;
 
46482
        }
 
46483
        case DUK_TOK_BXOR_EQ: {
 
46484
                /* right associative */
 
46485
                args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
 
46486
                goto assign;
 
46487
        }
 
46488
 
 
46489
        /* COMMA */
 
46490
 
 
46491
        case DUK_TOK_COMMA: {
 
46492
                /* right associative */
 
46493
 
 
46494
                duk__ivalue_toplain_ignore(comp_ctx, left);  /* need side effects, not value */
 
46495
                duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
 
46496
 
 
46497
                /* return 'res' (of right part) as our result */
 
46498
                return;
 
46499
        }
 
46500
 
 
46501
        default: {
 
46502
                break;
 
46503
        }
 
46504
        }
 
46505
 
 
46506
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "unexpected token to duk__expr_led(): %d", tok);
 
46507
        return;
 
46508
 
 
46509
#if 0
 
46510
        /* FIXME: shared handling for 'duk__expr_lhs'? */
 
46511
        if (comp_ctx->curr_func.paren_level == 0 && XXX) {
 
46512
                comp_ctx->curr_func.duk__expr_lhs = 0;
 
46513
        }
 
46514
#endif
 
46515
 
 
46516
 binary:
 
46517
        /*
 
46518
         *  Shared handling of binary operations
 
46519
         *
 
46520
         *  args = (opcode << 8) + rbp
 
46521
         */
 
46522
        {
 
46523
                duk__ivalue_toplain(comp_ctx, left);
 
46524
                duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
 
46525
 
 
46526
                /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
 
46527
                DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
 
46528
                DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
 
46529
 
 
46530
                res->t = DUK_IVAL_ARITH;
 
46531
                res->op = args >> 8;
 
46532
 
 
46533
                res->x2.t = res->x1.t;
 
46534
                res->x2.regconst = res->x1.regconst;
 
46535
                duk_dup(ctx, res->x1.valstack_idx);
 
46536
                duk_replace(ctx, res->x2.valstack_idx);
 
46537
 
 
46538
                res->x1.t = left->x1.t;
 
46539
                res->x1.regconst = left->x1.regconst;
 
46540
                duk_dup(ctx, left->x1.valstack_idx);
 
46541
                duk_replace(ctx, res->x1.valstack_idx);
 
46542
 
 
46543
                DUK_DDDPRINT("binary op, res: t=%d, x1.t=%d, x2.t=%d", res->t, res->x1.t, res->x2.t);
 
46544
                return;
 
46545
        }
 
46546
 
 
46547
 binary_logical:
 
46548
        /*
 
46549
         *  Shared handling for logical AND and logical OR.
 
46550
         *
 
46551
         *  args = (truthval << 8) + rbp
 
46552
         *
 
46553
         *  Truthval determines when to skip right-hand-side.
 
46554
         *  For logical AND truthval=1, for logical OR truthval=0.
 
46555
         *
 
46556
         *  See doc/compiler.txt for discussion on compiling logical
 
46557
         *  AND and OR expressions.  The approach here is very simplistic,
 
46558
         *  generating extra jumps and multiple evaluations of truth values,
 
46559
         *  but generates code on-the-fly with only local back-patching.
 
46560
         *
 
46561
         *  Both logical AND and OR are syntactically left-associated.
 
46562
         *  However, logical ANDs are compiled as right associative
 
46563
         *  expressions, i.e. "A && B && C" as "A && (B && C)", to allow
 
46564
         *  skip jumps to skip over the entire tail.  Similarly for logical OR.
 
46565
         */
 
46566
 
 
46567
        {
 
46568
                int reg_temp;
 
46569
                int pc_jump;
 
46570
                int args_truthval = args >> 8;
 
46571
                int args_rbp = args & 0xff;
 
46572
 
 
46573
                /* FIXME: unoptimal use of temps, resetting */
 
46574
 
 
46575
                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46576
 
 
46577
                duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
 
46578
                duk__emit_a_b(comp_ctx, DUK_OP_IF, args_truthval, reg_temp);  /* skip jump conditionally */
 
46579
                pc_jump = duk__emit_jump_empty(comp_ctx);
 
46580
                duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
 
46581
                duk__patch_jump_here(comp_ctx, pc_jump);
 
46582
 
 
46583
                res->t = DUK_IVAL_PLAIN;
 
46584
                res->x1.t = DUK_ISPEC_REGCONST;
 
46585
                res->x1.regconst = reg_temp;
 
46586
                return;
 
46587
        }
 
46588
 
 
46589
 assign:
 
46590
        /*
 
46591
         *  Shared assignment expression handling
 
46592
         *
 
46593
         *  args = (opcode << 8) + rbp
 
46594
         *
 
46595
         *  If 'opcode' is DUK_OP_INVALID, plain assignment without arithmetic.
 
46596
         *  Syntactically valid left-hand-side forms which are not accepted as
 
46597
         *  left-hand-side values (e.g. as in "f() = 1") must NOT cause a
 
46598
         *  SyntaxError, but rather a run-time ReferenceError.
 
46599
         */
 
46600
 
 
46601
        {
 
46602
                int args_op = args >> 8;
 
46603
                int args_rbp = args & 0xff;
 
46604
 
 
46605
                /* FIXME: here we need to know if 'left' is left-hand-side compatible.
 
46606
                 * That information is no longer available from current expr parsing
 
46607
                 * state; it would need to be carried into the 'left' ivalue or by
 
46608
                 * some other means.
 
46609
                 */
 
46610
 
 
46611
                if (left->t == DUK_IVAL_VAR) {
 
46612
                        duk_hstring *h_varname;
 
46613
                        int reg_varbind;
 
46614
                        int reg_varname;
 
46615
                        int reg_res;
 
46616
                        int reg_temp;
 
46617
 
 
46618
                        /* already in fluly evaluated form */
 
46619
                        DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE);
 
46620
 
 
46621
                        duk__expr_toreg(comp_ctx, res, args_rbp /*rbp_flags*/);
 
46622
                        DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
 
46623
 
 
46624
                        h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
 
46625
                        DUK_ASSERT(h_varname != NULL);
 
46626
 
 
46627
                        /* E5 Section 11.13.1 (and others for other assignments), step 4 */
 
46628
                        if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
 
46629
                                goto syntax_error_lvalue;
 
46630
                        }
 
46631
 
 
46632
                        duk_dup(ctx, left->x1.valstack_idx);
 
46633
                        (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname);
 
46634
 
 
46635
                        DUK_DDDPRINT("assign to '%!O' -> reg_varbind=%d, reg_varname=%d",
 
46636
                                     h_varname, reg_varbind, reg_varname);
 
46637
 
 
46638
                        if (args_op == DUK_OP_INVALID) {
 
46639
                                reg_res = res->x1.regconst;
 
46640
                        } else {
 
46641
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46642
                                if (reg_varbind >= 0) {
 
46643
                                        duk__emit_a_b_c(comp_ctx, args_op, reg_temp, reg_varbind, res->x1.regconst);
 
46644
                                } else {
 
46645
                                        duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, reg_temp, reg_varname);
 
46646
                                        duk__emit_a_b_c(comp_ctx, args_op, reg_temp, reg_temp, res->x1.regconst);
 
46647
                                }
 
46648
                                reg_res = reg_temp;
 
46649
                        }
 
46650
 
 
46651
                        if (reg_varbind >= 0) {
 
46652
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_varbind, reg_res);
 
46653
                        } else {
 
46654
                                /* Only a reg fits into 'A' and reg_res may be a const in
 
46655
                                 * straight assignment.
 
46656
                                 *
 
46657
                                 * XXX: here the current A/B/C split is suboptimal: we could
 
46658
                                 * just use 9 bits for reg_res (and support constants) and 17
 
46659
                                 * instead of 18 bits for the varname const index.
 
46660
                                 */
 
46661
                                if (DUK__ISCONST(comp_ctx, reg_res)) {
 
46662
                                        reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46663
                                        duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_temp, reg_res);
 
46664
                                        reg_res = reg_temp;
 
46665
                                }
 
46666
                                duk__emit_a_bc(comp_ctx,
 
46667
                                               DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
46668
                                               reg_res,
 
46669
                                               reg_varname);
 
46670
                        }
 
46671
 
 
46672
                        res->t = DUK_IVAL_PLAIN;
 
46673
                        res->x1.t = DUK_ISPEC_REGCONST;
 
46674
                        res->x1.regconst = reg_res;
 
46675
                } else if (left->t == DUK_IVAL_PROP) {
 
46676
                        /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
 
46677
                        int reg_obj;
 
46678
                        int reg_key;
 
46679
                        int reg_res;
 
46680
                        int reg_temp;
 
46681
 
 
46682
                        duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
 
46683
                        DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
 
46684
 
 
46685
                        /* Don't allow a constant for the object (even for a number etc), as
 
46686
                         * it goes into the 'A' field of the opcode.
 
46687
                         */
 
46688
 
 
46689
                        reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
 
46690
                        reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
46691
        
 
46692
                        if (args_op == DUK_OP_INVALID) {
 
46693
                                reg_res = res->x1.regconst;
 
46694
                        } else {
 
46695
                                reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46696
                                duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_temp, reg_obj, reg_key);
 
46697
                                duk__emit_a_b_c(comp_ctx, args_op, reg_temp, reg_temp, res->x1.regconst);
 
46698
                                reg_res = reg_temp;
 
46699
                        }
 
46700
 
 
46701
                        duk__emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_res);
 
46702
 
 
46703
                        res->t = DUK_IVAL_PLAIN;
 
46704
                        res->x1.t = DUK_ISPEC_REGCONST;
 
46705
                        res->x1.regconst = reg_res;
 
46706
                } else {
 
46707
                        /* No support for lvalues returned from new or function call expressions.
 
46708
                         * However, these must NOT cause compile-time SyntaxErrors, but run-time
 
46709
                         * ReferenceErrors.  Both left and right sides of the assignment must be
 
46710
                         * evaluated before throwing a ReferenceError.  For instance:
 
46711
                         *
 
46712
                         *     f() = g();
 
46713
                         *
 
46714
                         * must result in f() being evaluated, then g() being evaluated, and
 
46715
                         * finally, a ReferenceError being thrown.  See E5 Section 11.13.1.
 
46716
                         */
 
46717
 
 
46718
                        int reg_res;
 
46719
 
 
46720
                        /* first evaluate LHS fully to ensure all side effects are out */
 
46721
                        duk__ivalue_toplain_ignore(comp_ctx, left);
 
46722
 
 
46723
                        /* then evaluate RHS fully (its value becomes the expression value too) */
 
46724
                        reg_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
 
46725
        
 
46726
                        duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS);
 
46727
 
 
46728
                        /* FIXME: this value is irrelevant because of INVLHS? */
 
46729
 
 
46730
                        res->t = DUK_IVAL_PLAIN;
 
46731
                        res->x1.t = DUK_ISPEC_REGCONST;
 
46732
                        res->x1.regconst = reg_res;
 
46733
                }
 
46734
 
 
46735
                return;
 
46736
        }
 
46737
 
 
46738
 postincdec_extraop:
 
46739
        {
 
46740
                /*
 
46741
                 *  Post-increment/decrement will return the original value as its
 
46742
                 *  result value.  However, even that value will be coerced using
 
46743
                 *  ToNumber().
 
46744
                 *
 
46745
                 *  FIXME: the current solution for this is very ugly.
 
46746
                 *
 
46747
                 *  Note that post increment/decrement has a "no LineTerminator here"
 
46748
                 *  restriction.  This is handled by duk__expr_lbp(), which forcibly terminates
 
46749
                 *  the previous expression if a LineTerminator occurs before '++'/'--'.
 
46750
                 */
 
46751
 
 
46752
                int reg_res;
 
46753
                int args_op = args >> 8;
 
46754
 
 
46755
                reg_res = DUK__ALLOCTEMP(comp_ctx);
 
46756
 
 
46757
                if (left->t == DUK_IVAL_VAR) {
 
46758
                        duk_hstring *h_varname;
 
46759
                        int reg_varbind;
 
46760
                        int reg_varname;
 
46761
 
 
46762
                        h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
 
46763
                        DUK_ASSERT(h_varname != NULL);
 
46764
 
 
46765
                        if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
 
46766
                                goto syntax_error;
 
46767
                        }
 
46768
 
 
46769
                        duk_dup(ctx, left->x1.valstack_idx);
 
46770
                        if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
46771
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_res, reg_varbind);
 
46772
                                duk__emit_extraop_b_c(comp_ctx,
 
46773
                                                      DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET,
 
46774
                                                      reg_res,
 
46775
                                                      reg_res);
 
46776
                                duk__emit_extraop_b_c(comp_ctx,
 
46777
                                                      args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46778
                                                      reg_varbind,
 
46779
                                                      reg_res);
 
46780
                        } else {
 
46781
                                int reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46782
                                duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, reg_res, reg_varname);
 
46783
                                duk__emit_extraop_b_c(comp_ctx,
 
46784
                                                      DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET,
 
46785
                                                      reg_res,
 
46786
                                                      reg_res);
 
46787
                                duk__emit_extraop_b_c(comp_ctx,
 
46788
                                                      args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46789
                                                      reg_temp,
 
46790
                                                      reg_res);
 
46791
                                duk__emit_a_bc(comp_ctx,
 
46792
                                               DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
46793
                                               reg_temp,
 
46794
                                               reg_varname);
 
46795
                        }
 
46796
 
 
46797
                        DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%d, reg_varname=%d",
 
46798
                                     h_varname, reg_varbind, reg_varname);
 
46799
                } else if (left->t == DUK_IVAL_PROP) {
 
46800
                        int reg_obj;  /* allocate to reg only (not const) */
 
46801
                        int reg_key;
 
46802
                        int reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
46803
                        reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
 
46804
                        reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
46805
                        duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, reg_res, reg_obj, reg_key);
 
46806
                        duk__emit_extraop_b_c(comp_ctx,
 
46807
                                              DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET,
 
46808
                                              reg_res,
 
46809
                                              reg_res);
 
46810
                        duk__emit_extraop_b_c(comp_ctx,
 
46811
                                              args_op | DUK__EMIT_FLAG_B_IS_TARGET,
 
46812
                                              reg_temp,
 
46813
                                              reg_res);
 
46814
                        duk__emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_temp);
 
46815
                } else {
 
46816
                        /* Technically return value is not needed because INVLHS will
 
46817
                         * unconditially throw a ReferenceError.  Coercion is necessary
 
46818
                         * for proper semantics (consider ToNumber() called for an object).
 
46819
                         */
 
46820
                        duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
 
46821
                        duk__emit_extraop_b_c(comp_ctx,
 
46822
                                              DUK_EXTRAOP_TONUM | DUK__EMIT_FLAG_B_IS_TARGET,
 
46823
                                              reg_res,
 
46824
                                              reg_res);  /* for side effects */
 
46825
                        duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS);
 
46826
                }
 
46827
 
 
46828
                res->t = DUK_IVAL_PLAIN;
 
46829
                res->x1.t = DUK_ISPEC_REGCONST;
 
46830
                res->x1.regconst = reg_res;
 
46831
                DUK__SETTEMP(comp_ctx, reg_res + 1);
 
46832
                return;
 
46833
        }
 
46834
 
 
46835
 syntax_error:
 
46836
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid expression");
 
46837
        return;
 
46838
 
 
46839
 syntax_error_lvalue:
 
46840
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid lvalue");
 
46841
        return;
 
46842
}
 
46843
 
 
46844
static int duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
 
46845
        int tok = comp_ctx->curr_token.t;
 
46846
 
 
46847
        DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
 
46848
        DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
 
46849
 
 
46850
        /* FIXME: integrate support for this into led() instead?
 
46851
         * Similar issue as post-increment/post-decrement.
 
46852
         */
 
46853
 
 
46854
        /* prevent duk__expr_led() by using a binding power less than anything valid */
 
46855
        if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
 
46856
                return 0;
 
46857
        }
 
46858
 
 
46859
        if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
 
46860
            (comp_ctx->curr_token.lineterm)) {
 
46861
                /* '++' or '--' in a post-increment/decrement position,
 
46862
                 * and a LineTerminator occurs between the operator and
 
46863
                 * the preceding expression.  Force the previous expr
 
46864
                 * to terminate, in effect treating e.g. "a,b\n++" as
 
46865
                 * "a,b;++" (= SyntaxError).
 
46866
                 */
 
46867
                return 0;
 
46868
        }
 
46869
 
 
46870
        return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]);  /* format is bit packed */
 
46871
}
 
46872
 
 
46873
/*
 
46874
 *  Expression parsing.
 
46875
 *
 
46876
 *  Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
 
46877
 *  first token of the expression.  Upon exit, 'curr_tok' will be the first
 
46878
 *  token not part of the expression (e.g. semicolon terminating an expression
 
46879
 *  statement).
 
46880
 */
 
46881
 
 
46882
#define DUK__EXPR_RBP_MASK           0xff
 
46883
#define DUK__EXPR_FLAG_REJECT_IN     (1 << 8)
 
46884
#define DUK__EXPR_FLAG_ALLOW_EMPTY   (1 << 9)
 
46885
 
 
46886
/* main expression parser function */
 
46887
static void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46888
        duk_hthread *thr = comp_ctx->thr;
 
46889
        duk_context *ctx = (duk_context *) thr;
 
46890
        duk_ivalue tmp_alloc;   /* 'res' is used for "left", and 'tmp' for "right" */
 
46891
        duk_ivalue *tmp = &tmp_alloc;
 
46892
        int rbp;
 
46893
 
 
46894
        DUK__RECURSION_INCREASE(comp_ctx, thr);
 
46895
 
 
46896
        duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
 
46897
 
 
46898
        /* filter out flags from exprtop rbp_flags here to save space */
 
46899
        rbp = rbp_flags & DUK__EXPR_RBP_MASK;
 
46900
 
 
46901
        DUK_DDDPRINT("duk__expr(), rbp_flags=%d, rbp=%d, allow_in=%d, paren_level=%d",
 
46902
                     rbp_flags, rbp, comp_ctx->curr_func.allow_in, comp_ctx->curr_func.paren_level);
 
46903
 
 
46904
        DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
 
46905
        tmp->x1.valstack_idx = duk_get_top(ctx);
 
46906
        tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
 
46907
        duk_push_undefined(ctx);
 
46908
        duk_push_undefined(ctx);
 
46909
 
 
46910
        /* FIXME: where to release temp regs in intermediate expressions?
 
46911
         * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
 
46912
         * that particular expression temp regs can be forced here.
 
46913
         */
 
46914
 
 
46915
        /* FIXME: increase ctx->expr_tokens here for every consumed token
 
46916
         * (this would be a nice statistic)?
 
46917
         */
 
46918
 
 
46919
        if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
 
46920
                /* FIXME: incorrect hack for testing */
 
46921
                DUK_DDDPRINT("empty expression");
 
46922
                if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
 
46923
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "empty expression not allowed");
 
46924
                }
 
46925
                res->t = DUK_IVAL_PLAIN;
 
46926
                res->x1.t = DUK_ISPEC_VALUE;
 
46927
                duk_push_undefined(ctx);
 
46928
                duk_replace(ctx, res->x1.valstack_idx);
 
46929
                goto cleanup;
 
46930
        }
 
46931
 
 
46932
        duk__advance(comp_ctx);
 
46933
        duk__expr_nud(comp_ctx, res);  /* reuse 'res' as 'left' */
 
46934
        while (rbp < duk__expr_lbp(comp_ctx)) {
 
46935
                duk__advance(comp_ctx);
 
46936
                duk__expr_led(comp_ctx, res, tmp);
 
46937
                duk__copy_ivalue(comp_ctx, tmp, res);  /* tmp -> res */
 
46938
        }
 
46939
 
 
46940
 cleanup:
 
46941
        /* final result is already in 'res' */
 
46942
 
 
46943
        duk_pop_2(ctx);
 
46944
 
 
46945
        DUK__RECURSION_DECREASE(comp_ctx, thr);
 
46946
}
 
46947
 
 
46948
static void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46949
        duk_hthread *thr = comp_ctx->thr;
 
46950
 
 
46951
        /* Note: these variables must reside in 'curr_func' instead of the global
 
46952
         * context: when parsing function expressions, expression parsing is nested.
 
46953
         */
 
46954
        comp_ctx->curr_func.nud_count = 0;
 
46955
        comp_ctx->curr_func.led_count = 0;
 
46956
        comp_ctx->curr_func.paren_level = 0;
 
46957
        comp_ctx->curr_func.expr_lhs = 1;
 
46958
        comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
 
46959
 
 
46960
        duk__expr(comp_ctx, res, rbp_flags);
 
46961
 
 
46962
        if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
 
46963
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "empty expression not allowed");
 
46964
        }
 
46965
}
 
46966
 
 
46967
/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
 
46968
 * and result conversions.
 
46969
 *
 
46970
 * Each helper needs at least 2-3 calls to make it worth while to wrap.
 
46971
 */
 
46972
 
 
46973
static int duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46974
        duk__expr(comp_ctx, res, rbp_flags);
 
46975
        return duk__ivalue_toreg(comp_ctx, res);
 
46976
}
 
46977
 
 
46978
#if 0  /* unused */
 
46979
static int duk__expr_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46980
        duk__expr(comp_ctx, res, rbp_flags);
 
46981
        return duk__ivalue_totempreg(comp_ctx, res);
 
46982
}
 
46983
#endif
 
46984
 
 
46985
static int duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags, int forced_reg) {
 
46986
        duk__expr(comp_ctx, res, rbp_flags);
 
46987
        return duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
 
46988
}
 
46989
 
 
46990
static int duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46991
        duk__expr(comp_ctx, res, rbp_flags);
 
46992
        return duk__ivalue_toregconst(comp_ctx, res);
 
46993
}
 
46994
 
 
46995
static void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
46996
        duk__expr(comp_ctx, res, rbp_flags);
 
46997
        duk__ivalue_toplain(comp_ctx, res);
 
46998
}
 
46999
 
 
47000
static void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
47001
        duk__expr(comp_ctx, res, rbp_flags);
 
47002
        duk__ivalue_toplain_ignore(comp_ctx, res);
 
47003
}
 
47004
 
 
47005
static int duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
47006
        duk__exprtop(comp_ctx, res, rbp_flags);
 
47007
        return duk__ivalue_toreg(comp_ctx, res);
 
47008
}
 
47009
 
 
47010
#if 0  /* unused */
 
47011
static int duk__exprtop_totempreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
47012
        duk__exprtop(comp_ctx, res, rbp_flags);
 
47013
        return duk__ivalue_totempreg(comp_ctx, res);
 
47014
}
 
47015
#endif
 
47016
 
 
47017
#if 0  /* unused */
 
47018
static int duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags, int forced_reg) {
 
47019
        duk__exprtop(comp_ctx, res, rbp_flags);
 
47020
        return duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
 
47021
}
 
47022
#endif
 
47023
 
 
47024
static int duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
47025
        duk__exprtop(comp_ctx, res, rbp_flags);
 
47026
        return duk__ivalue_toregconst(comp_ctx, res);
 
47027
}
 
47028
 
 
47029
#if 0  /* unused */
 
47030
static void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
 
47031
        duk__exprtop(comp_ctx, res, rbp_flags);
 
47032
        duk__ivalue_toplain_ignore(comp_ctx, res);
 
47033
}
 
47034
#endif
 
47035
 
 
47036
/*
 
47037
 *  Parse an individual source element (top level statement) or a statement.
 
47038
 *
 
47039
 *  Handles labeled statements automatically (peeling away labels before
 
47040
 *  parsing an expression that follows the label(s)).
 
47041
 *
 
47042
 *  Upon entry, 'curr_tok' contains the first token of the statement (parsed
 
47043
 *  in "allow regexp literal" mode).  Upon exit, 'curr_tok' contains the first
 
47044
 *  token following the statement (if the statement has a terminator, this is
 
47045
 *  the token after the terminator).
 
47046
 */
 
47047
 
 
47048
#ifdef DUK__HAS_VAL
 
47049
#undef DUK__HAS_VAL
 
47050
#endif
 
47051
#ifdef DUK__HAS_TERM
 
47052
#undef DUK__HAS_TERM
 
47053
#endif
 
47054
#ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
 
47055
#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
 
47056
#endif
 
47057
#ifdef DUK__STILL_PROLOGUE
 
47058
#undef DUK__STILL_PROLOGUE
 
47059
#endif
 
47060
#ifdef DUK__IS_TERMINAL
 
47061
#undef DUK__IS_TERMINAL
 
47062
#endif
 
47063
 
 
47064
#define DUK__HAS_VAL                  (1 << 0)  /* stmt has non-empty value */
 
47065
#define DUK__HAS_TERM                 (1 << 1)  /* stmt has explicit/implicit semicolon terminator */
 
47066
#define DUK__ALLOW_AUTO_SEMI_ALWAYS   (1 << 2)  /* allow automatic semicolon even without lineterm (compatibility) */
 
47067
#define DUK__STILL_PROLOGUE           (1 << 3)  /* statement does not terminate directive prologue */
 
47068
#define DUK__IS_TERMINAL              (1 << 4)  /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
 
47069
 
 
47070
/* Parse a single variable declaration (e.g. "i" or "i=10").  A leading 'var'
 
47071
 * has already been eaten.  These is no return value in 'res', it is used only
 
47072
 * as a temporary.
 
47073
 *
 
47074
 * When called from 'for-in' statement parser, the initializer expression must
 
47075
 * not allow the 'in' token.  The caller supply additional expression parsing
 
47076
 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
 
47077
 *
 
47078
 * Finally, out_reg_varname and out_reg_varbind are updated to reflect where
 
47079
 * the identifier is bound:
 
47080
 *
 
47081
 *    If register bound:      out_reg_varbind >= 0, out_reg_varname < 0
 
47082
 *    If not register bound:  out_reg_varbind < 0, out_reg_varname >= 0
 
47083
 *
 
47084
 * These allow the caller to use the variable for further assignment, e.g.
 
47085
 * as is done in 'for-in' parsing.
 
47086
 */
 
47087
 
 
47088
static void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int expr_flags, int *out_reg_varname, int *out_reg_varbind) {
 
47089
        duk_hthread *thr = comp_ctx->thr;
 
47090
        duk_context *ctx = (duk_context *) thr;
 
47091
        duk_hstring *h_varname;
 
47092
        int reg_varname;
 
47093
        int reg_varbind;
 
47094
 
 
47095
        /* assume 'var' has been eaten */
 
47096
 
 
47097
        /* Note: Identifier rejects reserved words */
 
47098
        if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
 
47099
                goto syntax_error;
 
47100
        }
 
47101
        h_varname = comp_ctx->curr_token.str1;
 
47102
 
 
47103
        DUK_ASSERT(h_varname != NULL);
 
47104
 
 
47105
        /* strict mode restrictions (E5 Section 12.2.1) */
 
47106
        if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
 
47107
                goto syntax_error;
 
47108
        }
 
47109
 
 
47110
        /* register declarations in first pass */
 
47111
        if (comp_ctx->curr_func.in_scanning) {
 
47112
                int n;
 
47113
                DUK_DDDPRINT("register variable declaration %!O in pass 1", h_varname);
 
47114
                n = duk_get_length(ctx, comp_ctx->curr_func.decls_idx);  /*FIXME: primitive for pushing*/
 
47115
                duk_push_hstring(ctx, h_varname);
 
47116
                duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
 
47117
                duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
 
47118
                duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
 
47119
        }
 
47120
 
 
47121
        duk_push_hstring(ctx, h_varname);  /* push before advancing to keep reachable */
 
47122
 
 
47123
        /* register binding lookup is based on varmap (even in first pass) */
 
47124
        duk_dup_top(ctx);
 
47125
        (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname);
 
47126
 
 
47127
        duk__advance(comp_ctx);  /* eat identifier */
 
47128
 
 
47129
        if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
 
47130
                duk__advance(comp_ctx);
 
47131
 
 
47132
                DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%d, reg_varname=%d",
 
47133
                             h_varname, reg_varbind, reg_varname);
 
47134
 
 
47135
                duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/);  /* AssignmentExpression */
 
47136
 
 
47137
                if (reg_varbind >= 0) {
 
47138
                        duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
 
47139
                } else {
 
47140
                        int reg_val;
 
47141
                        reg_val = duk__ivalue_toreg(comp_ctx, res);
 
47142
                        duk__emit_a_bc(comp_ctx,
 
47143
                                       DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
47144
                                       reg_val,
 
47145
                                       reg_varname);
 
47146
                }
 
47147
        }
 
47148
 
 
47149
        duk_pop(ctx);  /* pop varname */
 
47150
 
 
47151
        *out_reg_varname = reg_varname;
 
47152
        *out_reg_varbind = reg_varbind;
 
47153
 
 
47154
        return;
 
47155
 
 
47156
 syntax_error:
 
47157
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid variable declaration");
 
47158
}
 
47159
 
 
47160
static void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47161
        int reg_varname;
 
47162
        int reg_varbind;
 
47163
 
 
47164
        duk__advance(comp_ctx);  /* eat 'var' */
 
47165
 
 
47166
        for (;;) {
 
47167
                /* reg_varname and reg_varbind are ignored here */
 
47168
                duk__parse_var_decl(comp_ctx, res, 0, &reg_varname, &reg_varbind);
 
47169
 
 
47170
                if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
 
47171
                        break;
 
47172
                }
 
47173
                duk__advance(comp_ctx);
 
47174
        } 
 
47175
}
 
47176
 
 
47177
static void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site) {
 
47178
        duk_hthread *thr = comp_ctx->thr;
 
47179
        duk_context *ctx = (duk_context *) thr;
 
47180
        int pc_v34_lhs;    /* start variant 3/4 left-hand-side code (L1 in doc/compiler.txt example) */
 
47181
        int temp_reset;    /* knock back "next temp" to this whenever possible */
 
47182
        int reg_temps;     /* preallocated temporaries (2) for variants 3 and 4 */
 
47183
 
 
47184
        DUK_DDDPRINT("start parsing a for/for-in statement");
 
47185
 
 
47186
        /* Two temporaries are preallocated here for variants 3 and 4 which need
 
47187
         * registers which are never clobbered by expressions in the loop
 
47188
         * (concretely: for the enumerator object and the next enumerated value).
 
47189
         * Variants 1 and 2 "release" these temps.
 
47190
         */
 
47191
 
 
47192
        reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
 
47193
 
 
47194
        temp_reset = DUK__GETTEMP(comp_ctx);
 
47195
 
 
47196
        /*
 
47197
         *  For/for-in main variants are:
 
47198
         *
 
47199
         *    1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
 
47200
         *    2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
 
47201
         *    3. for (LeftHandSideExpression in Expression) Statement
 
47202
         *    4. for (var VariableDeclarationNoIn in Expression) Statement
 
47203
         *
 
47204
         *  Parsing these without arbitrary lookahead or backtracking is relatively
 
47205
         *  tricky but we manage to do so for now.
 
47206
         *
 
47207
         *  See doc/compiler.txt for a detailed discussion of control flow
 
47208
         *  issues, evaluation order issues, etc.
 
47209
         */
 
47210
        
 
47211
        duk__advance(comp_ctx);  /* eat 'for' */
 
47212
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
47213
 
 
47214
        DUK_DDDPRINT("detecting for/for-in loop variant, pc=%d", duk__get_current_pc(comp_ctx));
 
47215
 
 
47216
        /* a label site has been emitted by duk__parse_stmt() automatically
 
47217
         * (it will also emit the ENDLABEL).
 
47218
         */
 
47219
 
 
47220
        if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
 
47221
                /*
 
47222
                 *  Variant 2 or 4
 
47223
                 */
 
47224
 
 
47225
                int reg_varname;  /* variable name reg/const, if variable not register-bound */
 
47226
                int reg_varbind;  /* variable binding register if register-bound (otherwise < 0) */
 
47227
 
 
47228
                duk__advance(comp_ctx);  /* eat 'var' */
 
47229
                duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varname, &reg_varbind);
 
47230
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47231
 
 
47232
                if (comp_ctx->curr_token.t == DUK_TOK_IN) {
 
47233
                        /*
 
47234
                         *  Variant 4
 
47235
                         */
 
47236
 
 
47237
                        DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement");
 
47238
                        pc_v34_lhs = duk__get_current_pc(comp_ctx);  /* jump is inserted here */
 
47239
                        if (reg_varbind >= 0) {
 
47240
                                duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_varbind, reg_temps + 0);
 
47241
                        } else {
 
47242
                                duk__emit_a_bc(comp_ctx,
 
47243
                                               DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
47244
                                               reg_temps + 0,
 
47245
                                               reg_varname);
 
47246
                        }
 
47247
                        goto parse_3_or_4;
 
47248
                } else {
 
47249
                        /*
 
47250
                         *  Variant 2
 
47251
                         */
 
47252
 
 
47253
                        DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement");
 
47254
                        for (;;) {
 
47255
                                /* more initializers */
 
47256
                                if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
 
47257
                                        break;
 
47258
                                }
 
47259
                                DUK_DDDPRINT("variant 2 has another variable initializer");
 
47260
 
 
47261
                                duk__advance(comp_ctx);  /* eat comma */
 
47262
                                duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varname, &reg_varbind);
 
47263
                        }
 
47264
                        goto parse_1_or_2;
 
47265
                }
 
47266
        } else {
 
47267
                /*
 
47268
                 *  Variant 1 or 3
 
47269
                 */
 
47270
 
 
47271
                pc_v34_lhs = duk__get_current_pc(comp_ctx);  /* jump is inserted here (variant 3) */
 
47272
 
 
47273
                /* FIXME: note that duk__exprtop() here can clobber any reg above current temp_next,
 
47274
                 * so any loop variables (e.g. enumerator) must be *preallocated* ... */
 
47275
 
 
47276
                /* don't coerce yet to a plain value (variant 3 needs special handling) */
 
47277
                duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression */
 
47278
                if (comp_ctx->curr_token.t == DUK_TOK_IN) {
 
47279
                        /*
 
47280
                         *  Variant 3
 
47281
                         */
 
47282
 
 
47283
                        /* FIXME: need to determine LHS type, and check that it is LHS compatible */
 
47284
                        DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement");
 
47285
                        if (duk__expr_is_empty(comp_ctx)) {
 
47286
                                goto syntax_error;  /* LeftHandSideExpression does not allow empty expression */
 
47287
                        }
 
47288
 
 
47289
                        if (res->t == DUK_IVAL_VAR) {
 
47290
                                int reg_varname;
 
47291
                                int reg_varbind;
 
47292
 
 
47293
                                duk_dup(ctx, res->x1.valstack_idx);
 
47294
                                if (duk__lookup_lhs(comp_ctx, &reg_varbind, &reg_varname)) {
 
47295
                                        duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, reg_varbind, reg_temps + 0);
 
47296
                                } else {
 
47297
                                        duk__emit_a_bc(comp_ctx,
 
47298
                                                       DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
47299
                                                       reg_temps + 0,
 
47300
                                                       reg_varname);
 
47301
                                }
 
47302
                        } else if (res->t == DUK_IVAL_PROP) {
 
47303
                                /* Don't allow a constant for the object (even for a number etc), as
 
47304
                                 * it goes into the 'A' field of the opcode.
 
47305
                                 */
 
47306
                                int reg_obj;
 
47307
                                int reg_key;
 
47308
                                reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
 
47309
                                reg_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
 
47310
                                duk__emit_a_b_c(comp_ctx, DUK_OP_PUTPROP, reg_obj, reg_key, reg_temps + 0);
 
47311
                        } else {
 
47312
                                duk__ivalue_toplain_ignore(comp_ctx, res);  /* just in case */
 
47313
                                duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_INVLHS);
 
47314
                        }
 
47315
                        goto parse_3_or_4;
 
47316
                } else {
 
47317
                        /*
 
47318
                         *  Variant 1
 
47319
                         */
 
47320
 
 
47321
                        DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement");
 
47322
                        duk__ivalue_toplain_ignore(comp_ctx, res);
 
47323
                        goto parse_1_or_2;
 
47324
                }
 
47325
        }
 
47326
 
 
47327
 parse_1_or_2:
 
47328
        /*
 
47329
         *  Parse variant 1 or 2.  The first part expression (which differs
 
47330
         *  in the variants) has already been parsed and its code emitted.
 
47331
         *
 
47332
         *  reg_temps + 0: unused
 
47333
         *  reg_temps + 1: unused
 
47334
         */
 
47335
        {
 
47336
                int reg_cond;
 
47337
                int pc_l1, pc_l2, pc_l3, pc_l4;
 
47338
                int pc_jumpto_l3, pc_jumpto_l4;
 
47339
                int expr_c_empty;
 
47340
 
 
47341
                DUK_DDDPRINT("shared code for parsing variants 1 and 2");
 
47342
 
 
47343
                /* "release" preallocated temps since we won't need them */
 
47344
                temp_reset = reg_temps + 0;
 
47345
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47346
 
 
47347
                duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
 
47348
 
 
47349
                pc_l1 = duk__get_current_pc(comp_ctx);
 
47350
                duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression_opt */
 
47351
                if (duk__expr_is_empty(comp_ctx)) {
 
47352
                        /* no need to coerce */
 
47353
                        pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* to body */
 
47354
                        pc_jumpto_l4 = -1;  /* omitted */
 
47355
                } else {
 
47356
                        reg_cond = duk__ivalue_toregconst(comp_ctx, res);
 
47357
                        duk__emit_if_false_skip(comp_ctx, reg_cond);
 
47358
                        pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* to body */
 
47359
                        pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);  /* to exit */
 
47360
                }
 
47361
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47362
 
 
47363
                duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
 
47364
 
 
47365
                pc_l2 = duk__get_current_pc(comp_ctx);
 
47366
                duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression_opt */
 
47367
                if (duk__expr_is_empty(comp_ctx)) {
 
47368
                        /* no need to coerce */
 
47369
                        expr_c_empty = 1;
 
47370
                        /* JUMP L1 omitted */
 
47371
                } else {
 
47372
                        duk__ivalue_toplain_ignore(comp_ctx, res);
 
47373
                        expr_c_empty = 0;
 
47374
                        duk__emit_jump(comp_ctx, pc_l1);
 
47375
                }
 
47376
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47377
 
 
47378
                duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47379
 
 
47380
                pc_l3 = duk__get_current_pc(comp_ctx);
 
47381
                duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47382
                if (expr_c_empty) {
 
47383
                        duk__emit_jump(comp_ctx, pc_l1);
 
47384
                } else {
 
47385
                        duk__emit_jump(comp_ctx, pc_l2);
 
47386
                }
 
47387
                /* temp reset is not necessary after duk__parse_stmt(), which already does it */
 
47388
 
 
47389
                pc_l4 = duk__get_current_pc(comp_ctx);
 
47390
 
 
47391
                DUK_DDDPRINT("patching jumps: jumpto_l3: %d->%d, jumpto_l4: %d->%d, "
 
47392
                             "break: %d->%d, continue: %d->%d",
 
47393
                             pc_jumpto_l3, pc_l3, pc_jumpto_l4, pc_l4,
 
47394
                             pc_label_site + 1, pc_l4, pc_label_site + 2, pc_l2);
 
47395
 
 
47396
                duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
 
47397
                duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
 
47398
                duk__patch_jump(comp_ctx,
 
47399
                                pc_label_site + 1,
 
47400
                                pc_l4);                         /* break jump */
 
47401
                duk__patch_jump(comp_ctx,
 
47402
                                pc_label_site + 2,
 
47403
                                expr_c_empty ? pc_l1 : pc_l2);  /* continue jump */
 
47404
        }
 
47405
        goto finished;
 
47406
 
 
47407
 parse_3_or_4:
 
47408
        /*
 
47409
         *  Parse variant 3 or 4.
 
47410
         *
 
47411
         *  For variant 3 (e.g. "for (A in C) D;") the code for A (except the
 
47412
         *  final property/variable write) has already been emitted.  The first
 
47413
         *  instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
 
47414
         *  there to satisfy control flow needs.
 
47415
         *
 
47416
         *  For variant 4, if the variable declaration had an initializer
 
47417
         *  (e.g. "for (var A = B in C) D;") the code for the assignment
 
47418
         *  (B) has already been emitted.
 
47419
         *
 
47420
         *  Variables set before entering here:
 
47421
         *
 
47422
         *    pc_v34_lhs:    insert a "JUMP L2" here (see doc/compiler.txt example).
 
47423
         *    reg_temps + 0: iteration target value (written to LHS)
 
47424
         *    reg_temps + 1: enumerator object
 
47425
         */
 
47426
        {
 
47427
                int pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
 
47428
                int pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
 
47429
                int reg_target;
 
47430
 
 
47431
                DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%d", pc_v34_lhs);
 
47432
 
 
47433
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47434
 
 
47435
                /* First we need to insert a jump in the middle of previously
 
47436
                 * emitted code to get the control flow right.  No jumps can
 
47437
                 * cross the position where the jump is inserted.  See doc/compiler.txt
 
47438
                 * for discussion on the intricacies of control flow and side effects
 
47439
                 * for variants 3 and 4.
 
47440
                 */
 
47441
 
 
47442
                duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
 
47443
                pc_jumpto_l2 = pc_v34_lhs;  /* inserted jump */
 
47444
                pc_l1 = pc_v34_lhs + 1;     /* +1, right after inserted jump */
 
47445
 
 
47446
                /* The code for writing reg_temps + 0 to the left hand side has already
 
47447
                 * been emitted.
 
47448
                 */
 
47449
 
 
47450
                pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* -> loop body */
 
47451
 
 
47452
                duk__advance(comp_ctx);  /* eat 'in' */
 
47453
 
 
47454
                /* Parse enumeration target and initialize enumerator.  For 'null' and 'undefined',
 
47455
                 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
 
47456
                 * (E5 Section 12.6.4, step 3).  Note that INITENUM requires the value to be in a
 
47457
                 * register (constant not allowed).
 
47458
                 */
 
47459
 
 
47460
                pc_l2 = duk__get_current_pc(comp_ctx);
 
47461
                reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression */
 
47462
                duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_INITENUM, reg_temps + 1, reg_target);
 
47463
                pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
 
47464
                DUK__SETTEMP(comp_ctx, temp_reset);
 
47465
 
 
47466
                duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47467
 
 
47468
                pc_l3 = duk__get_current_pc(comp_ctx);
 
47469
                duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47470
                /* temp reset is not necessary after duk__parse_stmt(), which already does it */
 
47471
 
 
47472
                pc_l4 = duk__get_current_pc(comp_ctx);
 
47473
                duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_NEXTENUM, reg_temps + 0, reg_temps + 1);
 
47474
                pc_jumpto_l5 = duk__emit_jump_empty(comp_ctx);  /* NEXTENUM jump slot: executed when enum finished */
 
47475
                duk__emit_jump(comp_ctx, pc_l1);  /* jump to next loop, using reg_v34_iter as iterated value */
 
47476
 
 
47477
                pc_l5 = duk__get_current_pc(comp_ctx);
 
47478
 
 
47479
                /* XXX: since the enumerator may be a memory expensive object,
 
47480
                 * perhaps clear it explicitly here?  If so, break jump must
 
47481
                 * go through this clearing operation.
 
47482
                 */
 
47483
 
 
47484
                DUK_DDDPRINT("patching jumps: jumpto_l2: %d->%d, jumpto_l3: %d->%d, "
 
47485
                             "jumpto_l4: %d->%d, jumpto_l5: %d->%d, "
 
47486
                             "break: %d->%d, continue: %d->%d",
 
47487
                             pc_jumpto_l2, pc_l2, pc_jumpto_l3, pc_l3,
 
47488
                             pc_jumpto_l4, pc_l4, pc_jumpto_l5, pc_l5,
 
47489
                             pc_label_site + 1, pc_l5, pc_label_site + 2, pc_l4);
 
47490
 
 
47491
                duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
 
47492
                duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
 
47493
                duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
 
47494
                duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
 
47495
                duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5);  /* break jump */
 
47496
                duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4);  /* continue jump */
 
47497
        }
 
47498
        goto finished;
 
47499
 
 
47500
 finished:
 
47501
        DUK_DDDPRINT("end parsing a for/for-in statement");
 
47502
        return;
 
47503
 
 
47504
 syntax_error:          
 
47505
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid for statement");
 
47506
}
 
47507
 
 
47508
static void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site) {
 
47509
        duk_hthread *thr = comp_ctx->thr;
 
47510
        int temp_at_loop;
 
47511
        int reg_switch;        /* reg/const for switch value */
 
47512
        int reg_case;          /* reg/const for case value */
 
47513
        int reg_temp;          /* general temp register */
 
47514
        int pc_prevcase = -1;
 
47515
        int pc_prevstmt = -1;
 
47516
        int pc_default = -1;   /* -1 == not set, -2 == pending (next statement list) */
 
47517
 
 
47518
        /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
 
47519
 
 
47520
        /*
 
47521
         *  Switch is pretty complicated because of several conflicting concerns:
 
47522
         *
 
47523
         *    - Want to generate code without an intermediate representation,
 
47524
         *      i.e., in one go
 
47525
         *
 
47526
         *    - Case selectors are expressions, not values, and may thus e.g. throw
 
47527
         *      exceptions (which causes evaluation order concerns)
 
47528
         *
 
47529
         *    - Evaluation semantics of case selectors and default clause need to be 
 
47530
         *      carefully implemented to provide correct behavior even with case value
 
47531
         *      side effects
 
47532
         *
 
47533
         *    - Fall through case and default clauses; avoiding dead JUMPs if case
 
47534
         *      ends with an unconditional jump (a break or a continue)
 
47535
         *
 
47536
         *    - The same case value may occur multiple times, but evaluation rules
 
47537
         *      only process the first match before switching to a "propagation" mode
 
47538
         *      where case values are no longer evaluated
 
47539
         *
 
47540
         *  See E5 Section 12.11.  Also see doc/compiler.txt for compilation
 
47541
         *  discussion.
 
47542
         */
 
47543
 
 
47544
        duk__advance(comp_ctx);
 
47545
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
47546
        reg_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47547
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47548
        duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
 
47549
 
 
47550
        DUK_DDDPRINT("switch value in register %d", reg_switch);
 
47551
 
 
47552
        temp_at_loop = DUK__GETTEMP(comp_ctx);
 
47553
 
 
47554
        for (;;) {
 
47555
                int num_stmts;
 
47556
                int tok;
 
47557
 
 
47558
                /* sufficient for keeping temp reg numbers in check */
 
47559
                DUK__SETTEMP(comp_ctx, temp_at_loop);
 
47560
 
 
47561
                if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
 
47562
                        break;
 
47563
                }
 
47564
 
 
47565
                /*
 
47566
                 *  Parse a case or default clause.
 
47567
                 */
 
47568
 
 
47569
                if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
 
47570
                        /*
 
47571
                         *  Case clause.
 
47572
                         *
 
47573
                         *  Note: cannot use reg_case as a temp register (for SEQ target)
 
47574
                         *  because it may be a constant.
 
47575
                         */
 
47576
 
 
47577
                        duk__patch_jump_here(comp_ctx, pc_prevcase);  /* chain jumps for case
 
47578
                                                                       * evaluation and checking
 
47579
                                                                       */
 
47580
 
 
47581
                        duk__advance(comp_ctx);
 
47582
                        reg_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47583
                        duk__advance_expect(comp_ctx, DUK_TOK_COLON);
 
47584
 
 
47585
                        reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
47586
                        duk__emit_a_b_c(comp_ctx, DUK_OP_SEQ, reg_temp, reg_switch, reg_case);
 
47587
                        duk__emit_if_true_skip(comp_ctx, reg_temp);
 
47588
 
 
47589
                        /* jump to next case clause */
 
47590
                        pc_prevcase = duk__emit_jump_empty(comp_ctx);  /* no match, next case */
 
47591
 
 
47592
                        /* statements go here (if any) on next loop */
 
47593
                } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
 
47594
                        /*
 
47595
                         *  Default clause.
 
47596
                         */
 
47597
 
 
47598
                        if (pc_default >= 0) {
 
47599
                                goto syntax_error;
 
47600
                        }
 
47601
                        duk__advance(comp_ctx);
 
47602
                        duk__advance_expect(comp_ctx, DUK_TOK_COLON);
 
47603
 
 
47604
                        /* default clause matches next statement list (if any) */
 
47605
                        pc_default = -2;
 
47606
                } else {
 
47607
                        /* Code is not accepted before the first case/default clause */
 
47608
                        goto syntax_error;
 
47609
                }
 
47610
 
 
47611
                /*
 
47612
                 *  Parse code after the clause.  Possible terminators are
 
47613
                 *  'case', 'default', and '}'.
 
47614
                 *
 
47615
                 *  Note that there may be no code at all, not even an empty statement,
 
47616
                 *  between case clauses.  This must be handled just like an empty statement
 
47617
                 *  (omitting seemingly pointless JUMPs), to avoid situations like
 
47618
                 *  test-bug-case-fallthrough.js.
 
47619
                 */
 
47620
 
 
47621
                num_stmts = 0;
 
47622
                if (pc_default == -2) {
 
47623
                        pc_default = duk__get_current_pc(comp_ctx);
 
47624
                }
 
47625
 
 
47626
                /* Note: this is correct even for default clause statements:
 
47627
                 * they participate in 'fall-through' behavior even if the
 
47628
                 * default clause is in the middle.
 
47629
                 */
 
47630
                duk__patch_jump_here(comp_ctx, pc_prevstmt);  /* chain jumps for 'fall-through'
 
47631
                                                               * after a case matches.
 
47632
                                                               */
 
47633
 
 
47634
                for (;;) {
 
47635
                        tok = comp_ctx->curr_token.t;
 
47636
                        if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
 
47637
                            tok == DUK_TOK_RCURLY) {
 
47638
                                break;
 
47639
                        }
 
47640
                        num_stmts++;
 
47641
                        duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47642
                }
 
47643
 
 
47644
                /* fall-through jump to next code of next case (backpatched) */
 
47645
                pc_prevstmt = duk__emit_jump_empty(comp_ctx);
 
47646
 
 
47647
                /* FIXME: would be nice to omit this jump when the jump is not
 
47648
                 * reachable, at least in the obvious cases (such as the case
 
47649
                 * ending with a 'break'.
 
47650
                 *
 
47651
                 * Perhaps duk__parse_stmt() could provide some info on whether
 
47652
                 * the statement is a "dead end"?
 
47653
                 *
 
47654
                 * If implemented, just set pc_prevstmt to -1 when not needed.
 
47655
                 */
 
47656
        }
 
47657
 
 
47658
        DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
 
47659
        duk__advance(comp_ctx);
 
47660
 
 
47661
        /* default case control flow patchup; note that if pc_prevcase < 0
 
47662
         * (i.e. no case clauses), control enters default case automatically.
 
47663
         */
 
47664
        if (pc_default >= 0) {
 
47665
                /* default case exists: go there if no case matches */
 
47666
                duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
 
47667
        } else {
 
47668
                /* default case does not exist, or no statements present
 
47669
                 * after default case: finish case evaluation
 
47670
                 */
 
47671
                duk__patch_jump_here(comp_ctx, pc_prevcase);
 
47672
        }
 
47673
 
 
47674
        /* fall-through control flow patchup; note that pc_prevstmt may be
 
47675
         * < 0 (i.e. no case clauses), in which case this is a no-op.
 
47676
         */
 
47677
        duk__patch_jump_here(comp_ctx, pc_prevstmt);
 
47678
 
 
47679
        /* continue jump not patched, an INVALID opcode remains there */
 
47680
        duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
 
47681
 
 
47682
        /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
 
47683
         * then jump here.  The double jump will be eliminated by a
 
47684
         * peephole pass, resulting in an optimal jump here.  The label
 
47685
         * site jumps will remain in bytecode and will waste code size.
 
47686
         */
 
47687
 
 
47688
        return;
 
47689
 
 
47690
 syntax_error:
 
47691
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid switch statement");
 
47692
}
 
47693
 
 
47694
static void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47695
        int temp_reset;
 
47696
        int reg_cond;
 
47697
        int pc_jump_false;
 
47698
 
 
47699
        DUK_DDDPRINT("begin parsing if statement");
 
47700
 
 
47701
        temp_reset = DUK__GETTEMP(comp_ctx);
 
47702
 
 
47703
        duk__advance(comp_ctx);  /* eat 'if' */
 
47704
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
47705
 
 
47706
        reg_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47707
        duk__emit_if_true_skip(comp_ctx, reg_cond);
 
47708
        pc_jump_false = duk__emit_jump_empty(comp_ctx);  /* jump to end or else part */
 
47709
        DUK__SETTEMP(comp_ctx, temp_reset);
 
47710
 
 
47711
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47712
 
 
47713
        duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47714
 
 
47715
        /* The 'else' ambiguity is resolved by 'else' binding to the innermost
 
47716
         * construct, so greedy matching is correct here.
 
47717
         */
 
47718
 
 
47719
        if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
 
47720
                int pc_jump_end;
 
47721
 
 
47722
                DUK_DDDPRINT("if has else part");
 
47723
 
 
47724
                duk__advance(comp_ctx);
 
47725
 
 
47726
                pc_jump_end = duk__emit_jump_empty(comp_ctx);  /* jump from true part to end */
 
47727
                duk__patch_jump_here(comp_ctx, pc_jump_false);
 
47728
 
 
47729
                duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47730
 
 
47731
                duk__patch_jump_here(comp_ctx, pc_jump_end);
 
47732
        } else {
 
47733
                DUK_DDDPRINT("if does not have else part");
 
47734
 
 
47735
                duk__patch_jump_here(comp_ctx, pc_jump_false);
 
47736
        }
 
47737
 
 
47738
        DUK_DDDPRINT("end parsing if statement");
 
47739
}
 
47740
 
 
47741
static void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site) {
 
47742
        int reg_cond;
 
47743
        int pc_start;
 
47744
 
 
47745
        DUK_DDDPRINT("begin parsing do statement");
 
47746
 
 
47747
        duk__advance(comp_ctx);  /* eat 'do' */
 
47748
 
 
47749
        pc_start = duk__get_current_pc(comp_ctx);
 
47750
        duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47751
        duk__patch_jump_here(comp_ctx, pc_label_site + 2);  /* continue jump */
 
47752
 
 
47753
        duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
 
47754
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
47755
 
 
47756
        reg_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47757
        duk__emit_if_false_skip(comp_ctx, reg_cond);
 
47758
        duk__emit_jump(comp_ctx, pc_start);
 
47759
        /* no need to reset temps, as we're finished emitting code */
 
47760
 
 
47761
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47762
 
 
47763
        duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
 
47764
 
 
47765
        DUK_DDDPRINT("end parsing do statement");
 
47766
}
 
47767
 
 
47768
static void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int pc_label_site) {
 
47769
        int temp_reset;
 
47770
        int reg_cond;
 
47771
        int pc_start;
 
47772
        int pc_jump_false;
 
47773
 
 
47774
        DUK_DDDPRINT("begin parsing while statement");
 
47775
 
 
47776
        temp_reset = DUK__GETTEMP(comp_ctx);
 
47777
 
 
47778
        duk__advance(comp_ctx);  /* eat 'while' */
 
47779
 
 
47780
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
47781
 
 
47782
        pc_start = duk__get_current_pc(comp_ctx);
 
47783
        duk__patch_jump_here(comp_ctx, pc_label_site + 2);  /* continue jump */
 
47784
 
 
47785
        reg_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47786
        duk__emit_if_true_skip(comp_ctx, reg_cond);
 
47787
        pc_jump_false = duk__emit_jump_empty(comp_ctx);
 
47788
        DUK__SETTEMP(comp_ctx, temp_reset);
 
47789
 
 
47790
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
47791
 
 
47792
        duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
47793
        duk__emit_jump(comp_ctx, pc_start);
 
47794
 
 
47795
        duk__patch_jump_here(comp_ctx, pc_jump_false);
 
47796
        duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
 
47797
 
 
47798
        DUK_DDDPRINT("end parsing while statement");
 
47799
}
 
47800
 
 
47801
static void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47802
        duk_hthread *thr = comp_ctx->thr;
 
47803
        int is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
 
47804
        int label_id;
 
47805
        int label_catch_depth;
 
47806
        int label_pc;  /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
 
47807
        int label_is_closest;
 
47808
 
 
47809
        DUK_UNREF(res);
 
47810
 
 
47811
        duk__advance(comp_ctx);  /* eat 'break' or 'continue' */
 
47812
 
 
47813
        if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON ||  /* explicit semi follows */
 
47814
            comp_ctx->curr_token.lineterm ||                /* automatic semi will be inserted */
 
47815
            comp_ctx->curr_token.allow_auto_semi) {         /* automatic semi will be inserted */
 
47816
                /* break/continue without label */
 
47817
 
 
47818
                duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
 
47819
        } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
 
47820
                /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
 
47821
                DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
 
47822
                duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
 
47823
                duk__advance(comp_ctx);
 
47824
        } else {
 
47825
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid break/continue label");
 
47826
        }
 
47827
 
 
47828
        /* Use a fast break/continue when possible.  A fast break/continue is
 
47829
         * just a jump to the LABEL break/continue jump slot, which then jumps
 
47830
         * to an appropriate place (for break, going through ENDLABEL correctly).
 
47831
         * The peephole optimizer will optimize the jump to a direct one.
 
47832
         */
 
47833
 
 
47834
        if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
 
47835
            label_is_closest) {
 
47836
                DUK_DDDPRINT("break/continue: is_break=%d, label_id=%d, label_is_closest=%d, "
 
47837
                             "label_catch_depth=%d, catch_depth=%d "
 
47838
                             "-> use fast variant (direct jump)",
 
47839
                             is_break, label_id, label_is_closest, label_catch_depth,
 
47840
                             comp_ctx->curr_func.catch_depth);
 
47841
 
 
47842
                duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
 
47843
        } else {
 
47844
                DUK_DDDPRINT("break/continue: is_break=%d, label_id=%d, label_is_closest=%d, "
 
47845
                             "label_catch_depth=%d, catch_depth=%d "
 
47846
                             "-> use slow variant (longjmp)",
 
47847
                             is_break, label_id, label_is_closest, label_catch_depth,
 
47848
                             comp_ctx->curr_func.catch_depth);
 
47849
 
 
47850
                duk__emit_abc(comp_ctx,
 
47851
                              is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE,
 
47852
                              label_id);
 
47853
        }
 
47854
}
 
47855
 
 
47856
static void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47857
        duk_hthread *thr = comp_ctx->thr;
 
47858
        int reg_val;
 
47859
        int ret_flags;
 
47860
 
 
47861
        duk__advance(comp_ctx);  /* eat 'return' */
 
47862
 
 
47863
        /* A 'return' statement is only allowed inside an actual function body,
 
47864
         * not as part of eval or global code.
 
47865
         */
 
47866
        if (!comp_ctx->curr_func.is_function) {
 
47867
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid return");
 
47868
        }
 
47869
 
 
47870
        /* Use a fast return when possible.  A fast return does not cause a longjmp()
 
47871
         * unnecessarily.  A fast return can be done when no TCF catchers are active
 
47872
         * (this includes 'try' and 'with' statements).  Active label catches do not
 
47873
         * prevent a fast return; they're unwound on return automatically.
 
47874
         */
 
47875
 
 
47876
        ret_flags = 0;
 
47877
 
 
47878
        if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON ||  /* explicit semi follows */
 
47879
            comp_ctx->curr_token.lineterm ||                /* automatic semi will be inserted */
 
47880
            comp_ctx->curr_token.allow_auto_semi) {         /* automatic semi will be inserted */
 
47881
                DUK_DDDPRINT("empty return value -> undefined");
 
47882
                reg_val = 0;
 
47883
        } else {
 
47884
                int pc_before_expr;
 
47885
                int pc_after_expr;
 
47886
 
 
47887
                DUK_DDDPRINT("return with a value");
 
47888
 
 
47889
                DUK_UNREF(pc_before_expr);
 
47890
                DUK_UNREF(pc_after_expr);
 
47891
 
 
47892
                pc_before_expr = duk__get_current_pc(comp_ctx);
 
47893
                reg_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47894
                pc_after_expr = duk__get_current_pc(comp_ctx);
 
47895
 
 
47896
                /* Tail call check: if last opcode emitted was CALL, and
 
47897
                 * the context allows it, change the CALL to a tailcall.
 
47898
                 * The non-standard 'caller' property disables tail calls
 
47899
                 * because they pose some special cases which haven't been
 
47900
                 * fixed yet.
 
47901
                 */
 
47902
 
 
47903
#if !defined(DUK_USE_FUNC_NONSTD_CALLER_PROPERTY)
 
47904
                if (comp_ctx->curr_func.catch_depth == 0 &&   /* no catchers */
 
47905
                    pc_after_expr > pc_before_expr) {         /* at least one opcode emitted */
 
47906
                        duk_compiler_instr *instr;
 
47907
                        duk_small_int_t op;
 
47908
 
 
47909
                        instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
 
47910
                        DUK_ASSERT(instr != NULL);
 
47911
 
 
47912
                        op = DUK_DEC_OP(instr->ins);
 
47913
                        if (op == DUK_OP_CALL || op == DUK_OP_CALLI) {
 
47914
                                DUK_DDDPRINT("return statement detected a tail call opportunity: "
 
47915
                                             "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
 
47916
                                             "and last instruction is a CALL "
 
47917
                                             "-> set TAILCALL flag");
 
47918
                                /* just flip the single bit */
 
47919
                                instr->ins |= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL, 0, 0);
 
47920
 
 
47921
                                /* no need to emit a RETURN */
 
47922
                                return;
 
47923
                        }
 
47924
                }
 
47925
#endif  /* !DUK_USE_FUNC_NONSTD_CALLER_PROPERTY */
 
47926
 
 
47927
                ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
 
47928
        }
 
47929
 
 
47930
        if (comp_ctx->curr_func.catch_depth == 0) {
 
47931
                DUK_DDDPRINT("fast return allowed -> use fast return");
 
47932
                ret_flags |= DUK_BC_RETURN_FLAG_FAST;
 
47933
        } else {
 
47934
                DUK_DDDPRINT("fast return not allowed -> use slow return");
 
47935
        }
 
47936
 
 
47937
        duk__emit_a_b(comp_ctx, DUK_OP_RETURN, ret_flags /*flags*/, reg_val /*reg*/);
 
47938
}
 
47939
 
 
47940
static void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47941
        int reg_val;
 
47942
 
 
47943
        duk__advance(comp_ctx);  /* eat 'throw' */
 
47944
 
 
47945
        if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON ||  /* explicit semi follows */
 
47946
            comp_ctx->curr_token.lineterm ||                /* automatic semi will be inserted */
 
47947
            comp_ctx->curr_token.allow_auto_semi) {         /* automatic semi will be inserted */
 
47948
                DUK_DDDPRINT("empty throw value -> undefined");
 
47949
                reg_val = DUK__ALLOCTEMP(comp_ctx);
 
47950
                duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, reg_val);
 
47951
        } else {
 
47952
                DUK_DDDPRINT("throw with a value");
 
47953
 
 
47954
                /* FIXME: currently must be a register, not a const */
 
47955
                reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
47956
        }
 
47957
 
 
47958
        duk__emit_extraop_b_c(comp_ctx, DUK_EXTRAOP_THROW, reg_val, 0);
 
47959
}
 
47960
 
 
47961
static void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
47962
        duk_hthread *thr = comp_ctx->thr;
 
47963
        duk_context *ctx = (duk_context *) thr;
 
47964
        int reg_catch;      /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
 
47965
        int const_varname = 0;
 
47966
        int trycatch_flags = 0;
 
47967
        int pc_trycatch = -1;
 
47968
        int pc_catch = -1;
 
47969
        int pc_finally = -1;
 
47970
 
 
47971
        DUK_UNREF(res);
 
47972
 
 
47973
        /*
 
47974
         *  See the following documentation for discussion:
 
47975
         *
 
47976
         *    doc/execution.txt: control flow details
 
47977
         *
 
47978
         *  Try, catch, and finally "parts" are Blocks, not Statements, so
 
47979
         *  they must always be delimited by curly braces.  This is unlike e.g.
 
47980
         *  the if statement, which accepts any Statement.  This eliminates any
 
47981
         *  questions of matching parts of nested try statements.  The Block
 
47982
         *  parsing is implemented inline here (instead of calling out).
 
47983
         *
 
47984
         *  Finally part has a 'let scoped' variable, which requires a few kinks
 
47985
         *  here.
 
47986
         */
 
47987
 
 
47988
        comp_ctx->curr_func.catch_depth++;
 
47989
 
 
47990
        duk__advance(comp_ctx);  /* eat 'try' */
 
47991
 
 
47992
        reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
 
47993
 
 
47994
        pc_trycatch = duk__get_current_pc(comp_ctx);
 
47995
        duk__emit_invalid(comp_ctx);  /* TRYCATCH, cannot emit now (not enough info) */
 
47996
        duk__emit_invalid(comp_ctx);  /* jump for 'catch' case */
 
47997
        duk__emit_invalid(comp_ctx);  /* jump for 'finally' case or end (if no finally) */
 
47998
 
 
47999
        /* try part */
 
48000
        duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
 
48001
        duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
 
48002
        /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
 
48003
        duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_ENDTRY);
 
48004
 
 
48005
        if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
 
48006
                /*
 
48007
                 *  The catch variable must be updated to reflect the new allocated
 
48008
                 *  register for the duration of the catch clause.  We need to store
 
48009
                 *  and restore the original value for the varmap entry (if any).
 
48010
                 */
 
48011
 
 
48012
                /*
 
48013
                 *  Note: currently register bindings must be fixed for the entire
 
48014
                 *  function.  So, even though the catch variable is in a register
 
48015
                 *  we know, we must use an explicit environment record and slow path
 
48016
                 *  accesses to read/write the catch binding to make closures created
 
48017
                 *  within the catch clause work correctly.  This restriction should
 
48018
                 *  be fixable (at least in common cases) later.
 
48019
                 *
 
48020
                 *  See: test-bug-catch-binding-2.js.
 
48021
                 *
 
48022
                 *  FIXME: improve to get fast path access to most catch clauses.
 
48023
                 */
 
48024
 
 
48025
                duk_hstring *h_var;
 
48026
                int varmap_value;  /* for storing/restoring the varmap binding for catch variable */
 
48027
 
 
48028
                DUK_DDDPRINT("stack top at start of catch clause: %d", duk_get_top(ctx));
 
48029
 
 
48030
                trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
 
48031
 
 
48032
                pc_catch = duk__get_current_pc(comp_ctx);
 
48033
 
 
48034
                duk__advance(comp_ctx);
 
48035
                duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
48036
 
 
48037
                if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
 
48038
                        /* Identifier, i.e. don't allow reserved words */
 
48039
                        goto syntax_error;
 
48040
                }
 
48041
                h_var = comp_ctx->curr_token.str1;
 
48042
                DUK_ASSERT(h_var != NULL);
 
48043
 
 
48044
                duk_push_hstring(ctx, h_var);  /* keep in on valstack, use borrowed ref below */
 
48045
 
 
48046
                if (comp_ctx->curr_func.is_strict &&
 
48047
                    ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
 
48048
                     (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
 
48049
                        DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError");
 
48050
                        goto syntax_error;
 
48051
                }
 
48052
 
 
48053
                duk_dup_top(ctx);
 
48054
                const_varname = duk__getconst(comp_ctx);
 
48055
                DUK_DDDPRINT("catch clause, const_varname=0x%08x (%d)", const_varname, const_varname);
 
48056
 
 
48057
                duk__advance(comp_ctx);
 
48058
                duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
48059
 
 
48060
                duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
 
48061
 
 
48062
                DUK_DDDPRINT("varmap before modifying for catch clause: %!iT", duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx));
 
48063
 
 
48064
                duk_dup_top(ctx);
 
48065
                duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48066
                if (duk_is_undefined(ctx, -1)) {
 
48067
                        varmap_value = -2;
 
48068
                } else if (duk_is_null(ctx, -1)) {
 
48069
                        varmap_value = -1;
 
48070
                } else {
 
48071
                        DUK_ASSERT(duk_is_number(ctx, -1));
 
48072
                        varmap_value = duk_get_int(ctx, -1);
 
48073
                        DUK_ASSERT(varmap_value >= 0);
 
48074
                }
 
48075
                duk_pop(ctx);
 
48076
 
 
48077
#if 0  /* something like this is what we'd like to do, but it doesn't work for closures created inside the catch clause */
 
48078
                duk_dup_top(ctx);
 
48079
                duk_push_int(ctx, reg_catch + 0);
 
48080
                duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48081
#endif
 
48082
                duk_dup_top(ctx);
 
48083
                duk_push_null(ctx);
 
48084
                duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48085
 
 
48086
                duk__emit_a_bc(comp_ctx,
 
48087
                               DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
 
48088
                               reg_catch + 0 /*value*/,
 
48089
                               const_varname /*varname*/);
 
48090
 
 
48091
                DUK_DDDPRINT("varmap before parsing catch clause: %!iT", duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx));
 
48092
 
 
48093
                duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
 
48094
                /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
 
48095
 
 
48096
                if (varmap_value == -2) {
 
48097
                        /* not present */
 
48098
                        duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48099
                } else {
 
48100
                        if (varmap_value == -1) {
 
48101
                                duk_push_null(ctx);
 
48102
                        } else {
 
48103
                                DUK_ASSERT(varmap_value >= 0);
 
48104
                                duk_push_int(ctx, varmap_value);
 
48105
                        }
 
48106
                        duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48107
                }
 
48108
                /* varname is popped by above code */
 
48109
 
 
48110
                DUK_DDDPRINT("varmap after restore catch clause: %!iT", duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx));
 
48111
 
 
48112
                duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_ENDCATCH);
 
48113
 
 
48114
                /*
 
48115
                 *  FIXME: for now, indicate that an expensive catch binding
 
48116
                 *  declarative environment is always needed.  If we don't
 
48117
                 *  need it, we don't need the const_varname either.
 
48118
                 */
 
48119
 
 
48120
                trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
 
48121
 
 
48122
                DUK_DDDPRINT("stack top at end of catch clause: %d", duk_get_top(ctx));
 
48123
        }
 
48124
 
 
48125
        if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
 
48126
                trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
 
48127
 
 
48128
                pc_finally = duk__get_current_pc(comp_ctx);
 
48129
 
 
48130
                duk__advance(comp_ctx);
 
48131
 
 
48132
                duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
 
48133
                duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
 
48134
                /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
 
48135
                duk__emit_extraop_b(comp_ctx, DUK_EXTRAOP_ENDFIN, reg_catch);  /* rethrow */
 
48136
        }
 
48137
 
 
48138
        if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
 
48139
            !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
 
48140
                /* must have catch and/or finally */
 
48141
                goto syntax_error;
 
48142
        }
 
48143
 
 
48144
        duk__patch_trycatch(comp_ctx,
 
48145
                            pc_trycatch,
 
48146
                            reg_catch,
 
48147
                            const_varname,
 
48148
                            trycatch_flags);
 
48149
 
 
48150
        if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
 
48151
                DUK_ASSERT(pc_catch >= 0);
 
48152
                duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
 
48153
        }
 
48154
 
 
48155
        if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
 
48156
                DUK_ASSERT(pc_finally >= 0);
 
48157
                duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
 
48158
        } else {
 
48159
                /* without finally, the second jump slot is used to jump to end of stmt */
 
48160
                duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
 
48161
        }
 
48162
 
 
48163
        comp_ctx->curr_func.catch_depth--;
 
48164
        return;
 
48165
 
 
48166
 syntax_error:
 
48167
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid try statement");
 
48168
}
 
48169
 
 
48170
static void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
 
48171
        int pc_trycatch;
 
48172
        int pc_finished;
 
48173
        int reg_catch;
 
48174
        int reg_target;
 
48175
        int trycatch_flags;
 
48176
 
 
48177
        if (comp_ctx->curr_func.is_strict) {
 
48178
                DUK_ERROR(comp_ctx->thr, DUK_ERR_SYNTAX_ERROR, "with stmt in strict mode");
 
48179
        }
 
48180
 
 
48181
        comp_ctx->curr_func.catch_depth++;
 
48182
 
 
48183
        duk__advance(comp_ctx);  /* eat 'with' */
 
48184
 
 
48185
        reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
 
48186
 
 
48187
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
48188
        reg_target = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
48189
        duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
 
48190
 
 
48191
        pc_trycatch = duk__get_current_pc(comp_ctx);
 
48192
        trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
 
48193
        duk__emit_a_b_c(comp_ctx, DUK_OP_TRYCATCH, trycatch_flags /*a*/, reg_catch /*b*/, reg_target /*c*/);
 
48194
        duk__emit_invalid(comp_ctx);  /* catch jump */
 
48195
        duk__emit_invalid(comp_ctx);  /* finished jump */
 
48196
 
 
48197
        duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
 
48198
        duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_ENDTRY);
 
48199
 
 
48200
        pc_finished = duk__get_current_pc(comp_ctx);
 
48201
 
 
48202
        duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
 
48203
 
 
48204
        comp_ctx->curr_func.catch_depth--;
 
48205
}
 
48206
 
 
48207
static int duk__stmt_label_site(duk_compiler_ctx *comp_ctx, int label_id) {
 
48208
        /* if a site already exists, nop: max one label site per statement */
 
48209
        if (label_id >= 0) {
 
48210
                return label_id;
 
48211
        }
 
48212
 
 
48213
        label_id = comp_ctx->curr_func.label_next++;
 
48214
        DUK_DDDPRINT("allocated new label id for label site: %d", label_id);
 
48215
 
 
48216
        duk__emit_abc(comp_ctx, DUK_OP_LABEL, label_id);
 
48217
        duk__emit_invalid(comp_ctx);
 
48218
        duk__emit_invalid(comp_ctx);
 
48219
 
 
48220
        return label_id;
 
48221
}
 
48222
 
 
48223
/* Parse a single statement.
 
48224
 *
 
48225
 * Creates a label site (with an empty label) automatically for iteration
 
48226
 * statements.  Also "peels off" any label statements for explicit labels.
 
48227
 */
 
48228
static void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int allow_source_elem) {
 
48229
        duk_hthread *thr = comp_ctx->thr;
 
48230
        duk_context *ctx = (duk_context *) thr;
 
48231
        int dir_prol_at_entry;
 
48232
        int temp_at_entry;
 
48233
        int labels_len_at_entry;
 
48234
        int pc_at_entry;   /* assumed to also be PC of "LABEL" */
 
48235
        int stmt_id;
 
48236
        int stmt_flags = 0;
 
48237
        int label_id = -1;
 
48238
        int tok;
 
48239
 
 
48240
        DUK__RECURSION_INCREASE(comp_ctx, thr);
 
48241
 
 
48242
        temp_at_entry = DUK__GETTEMP(comp_ctx);
 
48243
        pc_at_entry = duk__get_current_pc(comp_ctx);
 
48244
        labels_len_at_entry = duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
 
48245
        stmt_id = comp_ctx->curr_func.stmt_next++;
 
48246
        dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
 
48247
 
 
48248
        DUK_UNREF(stmt_id);
 
48249
 
 
48250
        DUK_DDDPRINT("parsing a statement, stmt_id=%d, temp_at_entry=%d, labels_len_at_entry=%d, "
 
48251
                     "is_strict=%d, in_directive_prologue=%d, catch_depth=%d",
 
48252
                     stmt_id, temp_at_entry, labels_len_at_entry, comp_ctx->curr_func.is_strict,
 
48253
                     comp_ctx->curr_func.in_directive_prologue, comp_ctx->curr_func.catch_depth);
 
48254
 
 
48255
        /* The directive prologue flag is cleared by default so that it is
 
48256
         * unset for any recursive statement parsing.  It is only "revived"
 
48257
         * if a directive is detected.  (We could also make directives only
 
48258
         * allowed if 'allow_source_elem' was true.)
 
48259
         */
 
48260
        comp_ctx->curr_func.in_directive_prologue = 0;
 
48261
 
 
48262
 retry_parse:
 
48263
 
 
48264
        DUK_DDDPRINT("try stmt parse, stmt_id=%d, label_id=%d, allow_source_elem=%d, catch_depth=%d",
 
48265
                     stmt_id, label_id, allow_source_elem, comp_ctx->curr_func.catch_depth);
 
48266
 
 
48267
        /*
 
48268
         *  Detect iteration statements; if encountered, establish an
 
48269
         *  empty label.
 
48270
         */
 
48271
 
 
48272
        tok = comp_ctx->curr_token.t;
 
48273
        if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
 
48274
            tok == DUK_TOK_SWITCH) {
 
48275
                DUK_DDDPRINT("iteration/switch statement -> add empty label");
 
48276
 
 
48277
                label_id = duk__stmt_label_site(comp_ctx, label_id);
 
48278
                duk__add_label(comp_ctx,
 
48279
                               DUK_HTHREAD_STRING_EMPTY_STRING(thr),
 
48280
                               pc_at_entry /*pc_label*/,
 
48281
                               label_id);
 
48282
        }
 
48283
 
 
48284
        /*
 
48285
         *  Main switch for statement / source element type.
 
48286
         */
 
48287
 
 
48288
        switch (comp_ctx->curr_token.t) {
 
48289
        case DUK_TOK_FUNCTION: {
 
48290
                /*
 
48291
                 *  Function declaration, function expression, or (non-standard)
 
48292
                 *  function statement.
 
48293
                 *
 
48294
                 *  The E5 specification only allows function declarations at
 
48295
                 *  the top level (in "source elements").  An ExpressionStatement
 
48296
                 *  is explicitly not allowed to begin with a "function" keyword
 
48297
                 *  (E5 Section 12.4).  Hence any non-error semantics for such
 
48298
                 *  non-top-level statements are non-standard.  Duktape semantics
 
48299
                 *  for function statements are modelled after V8, see
 
48300
                 *  test-dev-func-decl-outside-top.js.
 
48301
                 */
 
48302
 
 
48303
#if defined(DUK_USE_FUNC_STMT)
 
48304
                /* Lenient: allow function declarations outside top level in
 
48305
                 * non-strict mode but reject them in strict mode.
 
48306
                 */
 
48307
                if (allow_source_elem || !comp_ctx->curr_func.is_strict)
 
48308
#else
 
48309
                /* Strict: never allow function declarations outside top level. */
 
48310
                if (allow_source_elem)
 
48311
#endif
 
48312
                {
 
48313
                        /* FunctionDeclaration: not strictly a statement but handled as such.
 
48314
                         *
 
48315
                         * O(depth^2) parse count for inner functions is handled by recording a
 
48316
                         * lexer offset on the first compilation pass, so that the function can
 
48317
                         * be efficiently skipped on the second pass.  This is encapsulated into
 
48318
                         * duk__parse_func_like_fnum().
 
48319
                         */
 
48320
 
 
48321
                        int fnum;
 
48322
 
 
48323
                        DUK_DDDPRINT("function declaration statement");
 
48324
 
 
48325
                        duk__advance(comp_ctx);  /* eat 'function' */
 
48326
                        fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
 
48327
 
 
48328
                        if (comp_ctx->curr_func.in_scanning) {
 
48329
                                int n;
 
48330
                                duk_hstring *h_funcname;
 
48331
 
 
48332
                                duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3);
 
48333
                                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);  /* -> [ ... func name ] */
 
48334
                                h_funcname = duk_get_hstring(ctx, -1);
 
48335
                                DUK_ASSERT(h_funcname != NULL);
 
48336
 
 
48337
                                DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %d", h_funcname, fnum);
 
48338
                                n = duk_get_length(ctx, comp_ctx->curr_func.decls_idx);  /*FIXME: primitive for pushing*/
 
48339
                                duk_push_hstring(ctx, h_funcname);
 
48340
                                duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
 
48341
                                duk_push_int(ctx, DUK_DECL_TYPE_FUNC + (fnum << 8));
 
48342
                                duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
 
48343
 
 
48344
                                duk_pop_n(ctx, 2);
 
48345
                        }
 
48346
 
 
48347
                        /* no statement value (unlike function expression) */
 
48348
                        stmt_flags = 0;
 
48349
                        break;
 
48350
                } else {
 
48351
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "function declaration outside top level");
 
48352
                }
 
48353
                break;
 
48354
        }
 
48355
        case DUK_TOK_LCURLY: {
 
48356
                DUK_DDDPRINT("block statement");
 
48357
                duk__advance(comp_ctx);
 
48358
                duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
 
48359
                /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
 
48360
                stmt_flags = 0;
 
48361
                break;
 
48362
        }
 
48363
        case DUK_TOK_VAR: {
 
48364
                DUK_DDDPRINT("variable declaration statement");
 
48365
                duk__parse_var_stmt(comp_ctx, res);
 
48366
                stmt_flags = DUK__HAS_TERM;
 
48367
                break;
 
48368
        }
 
48369
        case DUK_TOK_SEMICOLON: {
 
48370
                /* empty statement with an explicit semicolon */
 
48371
                DUK_DDDPRINT("empty statement");
 
48372
                stmt_flags = DUK__HAS_TERM;
 
48373
                break;
 
48374
        }
 
48375
        case DUK_TOK_IF: {
 
48376
                DUK_DDDPRINT("if statement");
 
48377
                duk__parse_if_stmt(comp_ctx, res);
 
48378
                stmt_flags = 0;
 
48379
                break;
 
48380
        }
 
48381
        case DUK_TOK_DO: {
 
48382
                /*
 
48383
                 *  Do-while statement is mostly trivial, but there is special
 
48384
                 *  handling for automatic semicolon handling (triggered by the
 
48385
                 *  DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
 
48386
                 *
 
48387
                 *    https://bugs.ecmascript.org/show_bug.cgi?id=8
 
48388
                 *
 
48389
                 *  See doc/compiler.txt for details.
 
48390
                 */
 
48391
                DUK_DDDPRINT("do statement");
 
48392
                DUK_ASSERT(label_id >= 0);
 
48393
                duk__update_label_flags(comp_ctx,
 
48394
                                        label_id,
 
48395
                                        DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
 
48396
                duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
 
48397
                stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS;  /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
 
48398
                break;
 
48399
        }
 
48400
        case DUK_TOK_WHILE: {
 
48401
                DUK_DDDPRINT("while statement");
 
48402
                DUK_ASSERT(label_id >= 0);
 
48403
                duk__update_label_flags(comp_ctx,
 
48404
                                        label_id,
 
48405
                                        DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
 
48406
                duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
 
48407
                stmt_flags = 0;
 
48408
                break;
 
48409
        }
 
48410
        case DUK_TOK_FOR: {
 
48411
                /*
 
48412
                 *  For/for-in statement is complicated to parse because
 
48413
                 *  determining the statement type (three-part for vs. a
 
48414
                 *  for-in) requires potential backtracking.
 
48415
                 *
 
48416
                 *  See the helper for the messy stuff.
 
48417
                 */
 
48418
                DUK_DDDPRINT("for/for-in statement");
 
48419
                DUK_ASSERT(label_id >= 0);
 
48420
                duk__update_label_flags(comp_ctx,
 
48421
                                        label_id,
 
48422
                                        DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
 
48423
                duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
 
48424
                stmt_flags = 0;
 
48425
                break;
 
48426
        }
 
48427
        case DUK_TOK_CONTINUE:
 
48428
        case DUK_TOK_BREAK: {
 
48429
                DUK_DDDPRINT("break/continue statement");
 
48430
                duk__parse_break_or_continue_stmt(comp_ctx, res);
 
48431
                stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
 
48432
                break;
 
48433
        }
 
48434
        case DUK_TOK_RETURN: {
 
48435
                DUK_DDDPRINT("return statement");
 
48436
                duk__parse_return_stmt(comp_ctx, res);
 
48437
                stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
 
48438
                break;
 
48439
        }
 
48440
        case DUK_TOK_WITH: {
 
48441
                DUK_DDDPRINT("with statement");
 
48442
                comp_ctx->curr_func.with_depth++;
 
48443
                duk__parse_with_stmt(comp_ctx, res);
 
48444
                comp_ctx->curr_func.with_depth--;
 
48445
                stmt_flags = 0;
 
48446
                break;
 
48447
        }
 
48448
        case DUK_TOK_SWITCH: {
 
48449
                /*
 
48450
                 *  The switch statement is pretty messy to compile.
 
48451
                 *  See the helper for details.
 
48452
                 */
 
48453
                DUK_DDDPRINT("switch statement");
 
48454
                DUK_ASSERT(label_id >= 0);
 
48455
                duk__update_label_flags(comp_ctx,
 
48456
                                        label_id,
 
48457
                                        DUK_LABEL_FLAG_ALLOW_BREAK);  /* don't allow continue */
 
48458
                duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
 
48459
                stmt_flags = 0;
 
48460
                break;
 
48461
        }
 
48462
        case DUK_TOK_THROW: {
 
48463
                DUK_DDDPRINT("throw statement");
 
48464
                duk__parse_throw_stmt(comp_ctx, res);
 
48465
                stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
 
48466
                break;
 
48467
        }
 
48468
        case DUK_TOK_TRY: {
 
48469
                DUK_DDDPRINT("try statement");
 
48470
                duk__parse_try_stmt(comp_ctx, res);
 
48471
                stmt_flags = 0;
 
48472
                break;
 
48473
        }
 
48474
        case DUK_TOK_DEBUGGER: {
 
48475
                DUK_DDDPRINT("debugger statement: ignored");
 
48476
                duk__advance(comp_ctx);
 
48477
                stmt_flags = DUK__HAS_TERM;
 
48478
                break;
 
48479
        }
 
48480
        default: {
 
48481
                /*
 
48482
                 *  Else, must be one of:
 
48483
                 *    - ExpressionStatement, possibly a directive (String)
 
48484
                 *    - LabelledStatement (Identifier followed by ':')
 
48485
                 *
 
48486
                 *  Expressions beginning with 'function' keyword are covered by a case
 
48487
                 *  above (such expressions are not allowed in standard E5 anyway).
 
48488
                 *  Also expressions starting with '{' are interpreted as block
 
48489
                 *  statements.  See E5 Section 12.4.
 
48490
                 *
 
48491
                 *  Directive detection is tricky; see E5 Section 14.1 on directive
 
48492
                 *  prologue.  A directive is an expression statement with a single
 
48493
                 *  string literal and an explicit or automatic semicolon.  Escape
 
48494
                 *  characters are significant and no parens etc are allowed:
 
48495
                 *
 
48496
                 *    'use strict';          // valid 'use strict' directive
 
48497
                 *    'use\u0020strict';     // valid directive, not a 'use strict' directive
 
48498
                 *    ('use strict');        // not a valid directive
 
48499
                 *
 
48500
                 *  The expression is determined to consist of a single string literal
 
48501
                 *  based on duk__expr_nud() and duk__expr_led() call counts.  The string literal
 
48502
                 *  of a 'use strict' directive is determined to lack any escapes based
 
48503
                 *  num_escapes count from the lexer.  Note that other directives may be
 
48504
                 *  allowed to contain escapes, so a directive with escapes does not
 
48505
                 *  terminate a directive prologue.
 
48506
                 *
 
48507
                 *  We rely on the fact that the expression parser will not emit any
 
48508
                 *  code for a single token expression.  However, it will generate an
 
48509
                 *  intermediate value which we will then successfully ignore.
 
48510
                 *
 
48511
                 *  A similar approach is used for labels.
 
48512
                 */
 
48513
 
 
48514
                int single_token;
 
48515
 
 
48516
                DUK_DDDPRINT("expression statement");
 
48517
                duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
 
48518
 
 
48519
                single_token = (comp_ctx->curr_func.nud_count == 1 &&  /* one token */
 
48520
                                comp_ctx->curr_func.led_count == 0);   /* no operators */
 
48521
 
 
48522
                if (single_token &&
 
48523
                    comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
 
48524
                    comp_ctx->curr_token.t == DUK_TOK_COLON) {
 
48525
                        /*
 
48526
                         *  Detected label
 
48527
                         */
 
48528
 
 
48529
                        duk_hstring *h_lab;
 
48530
 
 
48531
                        /* expected ival */
 
48532
                        DUK_ASSERT(res->t == DUK_IVAL_VAR);
 
48533
                        DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
 
48534
                        DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
 
48535
                        h_lab = comp_ctx->prev_token.str1;
 
48536
                        DUK_ASSERT(h_lab != NULL);
 
48537
 
 
48538
                        DUK_DDDPRINT("explicit label site for label '%!O'", h_lab);
 
48539
 
 
48540
                        duk__advance(comp_ctx);  /* eat colon */
 
48541
 
 
48542
                        label_id = duk__stmt_label_site(comp_ctx, label_id);
 
48543
 
 
48544
                        duk__add_label(comp_ctx,
 
48545
                                       h_lab,
 
48546
                                       pc_at_entry /*pc_label*/,
 
48547
                                       label_id);
 
48548
        
 
48549
                        /* a statement following a label cannot be a source element
 
48550
                         * (a function declaration).
 
48551
                         */
 
48552
                        allow_source_elem = 0;
 
48553
 
 
48554
                        DUK_DDDPRINT("label handled, retry statement parsing");
 
48555
                        goto retry_parse;
 
48556
                }
 
48557
 
 
48558
                stmt_flags = 0;
 
48559
 
 
48560
                if (dir_prol_at_entry &&                           /* still in prologue */
 
48561
                    single_token &&                                /* single string token */
 
48562
                    comp_ctx->prev_token.t == DUK_TOK_STRING) {
 
48563
                        /*
 
48564
                         *  Detected a directive
 
48565
 
 
48566
                         */
 
48567
                        duk_hstring *h_dir;
 
48568
 
 
48569
                        /* expected ival */
 
48570
                        DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
 
48571
                        DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
 
48572
                        DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
 
48573
                        h_dir = comp_ctx->prev_token.str1;
 
48574
                        DUK_ASSERT(h_dir != NULL);
 
48575
 
 
48576
                        stmt_flags |= DUK__STILL_PROLOGUE;
 
48577
 
 
48578
                        /* Note: escaped characters differentiate directives */
 
48579
 
 
48580
                        if (comp_ctx->prev_token.num_escapes > 0) {
 
48581
                                DUK_DDDPRINT("directive contains escapes: valid directive "
 
48582
                                             "but we ignore such directives");
 
48583
                        } else {
 
48584
                                /* FIXME: how to compare 'use strict' most compactly?
 
48585
                                 * We don't necessarily want to add it to the built-ins
 
48586
                                 * because it's not needed at run time.
 
48587
                                 */
 
48588
 
 
48589
                                if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
 
48590
                                    DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) {
 
48591
                                        DUK_DDDPRINT("use strict directive detected: strict flag %d -> %d",
 
48592
                                                     comp_ctx->curr_func.is_strict, 1);
 
48593
                                        comp_ctx->curr_func.is_strict = 1;
 
48594
                                } else {
 
48595
                                        DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
 
48596
                                                    "directive prologue", (duk_hobject *) h_dir);
 
48597
                                }
 
48598
                        }
 
48599
                } else {
 
48600
                        DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
 
48601
                                     "prologue terminated if still active");
 
48602
                }
 
48603
 
 
48604
                stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
 
48605
        }
 
48606
        }  /* end switch (tok) */
 
48607
 
 
48608
        /*
 
48609
         *  Statement value handling.
 
48610
         *
 
48611
         *  Global code and eval code has an implicit return value
 
48612
         *  which comes from the last statement with a value
 
48613
         *  (technically a non-"empty" continuation, which is
 
48614
         *  different from an empty statement).
 
48615
         *
 
48616
         *  Since we don't know whether a later statement will
 
48617
         *  override the value of the current statement, we need
 
48618
         *  to coerce the statement value to a register allocated
 
48619
         *  for implicit return values.  In other cases we need
 
48620
         *  to coerce the statement value to a plain value to get
 
48621
         *  any side effects out (consider e.g. "foo.bar;").
 
48622
         */
 
48623
 
 
48624
        /* FIXME: what about statements which leave a half-cooked value in 'res'
 
48625
         * but have no stmt value?  Any such statements?
 
48626
         */
 
48627
 
 
48628
        if (stmt_flags & DUK__HAS_VAL) {
 
48629
                int reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
 
48630
                if (reg_stmt_value >= 0) {
 
48631
                        duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
 
48632
                } else {
 
48633
                        duk__ivalue_toplain_ignore(comp_ctx, res);
 
48634
                }
 
48635
        } else {
 
48636
                ;
 
48637
        }
 
48638
 
 
48639
        /*
 
48640
         *  Statement terminator check, including automatic semicolon
 
48641
         *  handling.  After this step, 'curr_tok' should be the first
 
48642
         *  token after a possible statement terminator.
 
48643
         */
 
48644
 
 
48645
        if (stmt_flags & DUK__HAS_TERM) {
 
48646
                if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
 
48647
                        DUK_DDDPRINT("explicit semicolon terminates statement");
 
48648
                        duk__advance(comp_ctx);
 
48649
                } else {
 
48650
                        if (comp_ctx->curr_token.allow_auto_semi) {
 
48651
                                DUK_DDDPRINT("automatic semicolon terminates statement");
 
48652
                        } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
 
48653
                                /* FIXME: make this lenience dependent on flags or strictness? */
 
48654
                                DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
 
48655
                                             "even though no lineterm present before next token)");
 
48656
                        } else {
 
48657
                                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "unterminated statement");
 
48658
                        }
 
48659
                }
 
48660
        } else {
 
48661
                DUK_DDDPRINT("statement has no terminator");
 
48662
        }
 
48663
 
 
48664
        /*
 
48665
         *  Directive prologue tracking.
 
48666
         */
 
48667
 
 
48668
        if (stmt_flags & DUK__STILL_PROLOGUE) {
 
48669
                DUK_DDDPRINT("setting in_directive_prologue");
 
48670
                comp_ctx->curr_func.in_directive_prologue = 1;
 
48671
        }
 
48672
 
 
48673
        /*
 
48674
         *  Cleanups (all statement parsing flows through here).
 
48675
         *
 
48676
         *  Pop label site and reset labels.  Reset 'next temp' to value at
 
48677
         *  entry to reuse temps.
 
48678
         */
 
48679
 
 
48680
        if (label_id >= 0) {
 
48681
                duk__emit_abc(comp_ctx, DUK_OP_ENDLABEL, label_id);
 
48682
        }
 
48683
 
 
48684
        DUK__SETTEMP(comp_ctx, temp_at_entry);
 
48685
 
 
48686
        duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
 
48687
 
 
48688
        /* FIXME: return indication of "terminalness" (e.g. a 'throw' is terminal) */
 
48689
 
 
48690
        DUK__RECURSION_DECREASE(comp_ctx, thr);
 
48691
}
 
48692
 
 
48693
#undef DUK__HAS_VAL
 
48694
#undef DUK__HAS_TERM
 
48695
#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
 
48696
 
 
48697
/*
 
48698
 *  Parse a statement list.
 
48699
 *
 
48700
 *  Handles automatic semicolon insertion and implicit return value.
 
48701
 *
 
48702
 *  Upon entry, 'curr_tok' should contain the first token of the first
 
48703
 *  statement (parsed in the "allow regexp literal" mode).  Upon exit,
 
48704
 *  'curr_tok' contains the token following the statement list terminator
 
48705
 *  (EOF or closing brace).
 
48706
 */
 
48707
 
 
48708
static void duk__parse_stmts(duk_compiler_ctx *comp_ctx, int allow_source_elem, int expect_eof) {
 
48709
        duk_hthread *thr = comp_ctx->thr;
 
48710
        duk_context *ctx = (duk_context *) thr;
 
48711
        duk_ivalue res_alloc;
 
48712
        duk_ivalue *res = &res_alloc;
 
48713
 
 
48714
        /* Setup state.  Initial ivalue is 'undefined'. */
 
48715
 
 
48716
        duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
 
48717
 
 
48718
        /* FIXME: 'res' setup can be moved to function body level; in fact, two 'res'
 
48719
         * intermediate values suffice for parsing of each function.  Nesting is needed
 
48720
         * for nested functions (which may occur inside expressions).
 
48721
         */
 
48722
 
 
48723
        DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
 
48724
        res->t = DUK_IVAL_PLAIN;
 
48725
        res->x1.t = DUK_ISPEC_VALUE;
 
48726
        res->x1.valstack_idx = duk_get_top(ctx);
 
48727
        res->x2.valstack_idx = res->x1.valstack_idx + 1;
 
48728
        duk_push_undefined(ctx);
 
48729
        duk_push_undefined(ctx);
 
48730
 
 
48731
        /* Parse statements until a closing token (EOF or '}') is found. */
 
48732
 
 
48733
        for (;;) {
 
48734
                /* Check whether statement list ends. */
 
48735
 
 
48736
                if (expect_eof) {
 
48737
                        if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
 
48738
                                break;
 
48739
                        }
 
48740
                } else {
 
48741
                        if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
 
48742
                                break;
 
48743
                        }
 
48744
                }
 
48745
 
 
48746
                /* Check statement type based on the first token type.
 
48747
                 *
 
48748
                 * Note: expression parsing helpers expect 'curr_tok' to
 
48749
                 * contain the first token of the expression upon entry.
 
48750
                 */
 
48751
 
 
48752
                DUK_DDDPRINT("TOKEN %d (non-whitespace, non-comment)", comp_ctx->curr_token.t);
 
48753
 
 
48754
                duk__parse_stmt(comp_ctx, res, allow_source_elem);
 
48755
        }
 
48756
 
 
48757
        duk__advance(comp_ctx);
 
48758
 
 
48759
        /* Tear down state. */
 
48760
 
 
48761
        duk_pop_2(ctx);
 
48762
}
 
48763
 
 
48764
/*
 
48765
 *  Declaration binding instantiation conceptually happens when calling a
 
48766
 *  function; for us it essentially means that function prologue.  The
 
48767
 *  conceptual process is described in E5 Section 10.5.
 
48768
 *
 
48769
 *  We need to keep track of all encountered identifiers to (1) create an
 
48770
 *  identifier-to-register map ("varmap"); and (2) detect duplicate
 
48771
 *  declarations.  Identifiers which are not bound to registers still need
 
48772
 *  to be tracked for detecting duplicates.  Currently such identifiers
 
48773
 *  are put into the varmap with a 'null' value, which is later cleaned up.
 
48774
 *
 
48775
 *  To support functions with a large number of variable and function
 
48776
 *  declarations, registers are not allocated beyond a certain limit;
 
48777
 *  after that limit, variables and functions need slow path access.
 
48778
 *  Arguments are currently always register bound, which imposes a hard
 
48779
 *  (and relatively small) argument count limit.
 
48780
 *
 
48781
 *  Some bindings in E5 are not configurable (= deletable) and almost all
 
48782
 *  are mutable (writable).  Exceptions are:
 
48783
 * 
 
48784
 *    - The 'arguments' binding, established only if no shadowing argument
 
48785
 *      or function declaration exists.  We handle 'arguments' creation
 
48786
 *      and binding through an explicit slow path environment record.
 
48787
 *
 
48788
 *    - The "name" binding for a named function expression.  This is also
 
48789
 *      handled through an explicit slow path environment record.
 
48790
 */
 
48791
 
 
48792
/* FIXME: add support for variables to not be register bound always, to 
 
48793
 * handle cases with a very large number of variables?
 
48794
 */
 
48795
 
 
48796
static void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, int *out_stmt_value_reg) {
 
48797
        duk_hthread *thr = comp_ctx->thr;
 
48798
        duk_context *ctx = (duk_context *) thr;
 
48799
        duk_hstring *h_name;
 
48800
        int configurable_bindings;
 
48801
        int num_args;
 
48802
        int num_decls;
 
48803
        int reg_name;
 
48804
        int declvar_flags;
 
48805
        int i;
 
48806
#ifdef DUK_USE_ASSERTIONS
 
48807
        int entry_top;
 
48808
#endif
 
48809
 
 
48810
#ifdef DUK_USE_ASSERTIONS
 
48811
        entry_top = duk_get_top(ctx);
 
48812
#endif
 
48813
 
 
48814
        /*
 
48815
         *  Preliminaries
 
48816
         */
 
48817
 
 
48818
        configurable_bindings = comp_ctx->curr_func.is_eval;
 
48819
        DUK_DDDPRINT("configurable_bindings=%d", configurable_bindings);
 
48820
 
 
48821
        /* varmap is already in comp_ctx->curr_func.varmap_idx */
 
48822
 
 
48823
        /*
 
48824
         *  Function formal arguments, always bound to registers
 
48825
         *  (there's no support for shuffling them now).
 
48826
         */
 
48827
 
 
48828
        num_args = duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
 
48829
        DUK_DDDPRINT("num_args=%d", num_args);
 
48830
        /* FIXME: check num_args */
 
48831
 
 
48832
        for (i = 0; i < num_args; i++) {
 
48833
                duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
 
48834
                h_name = duk_get_hstring(ctx, -1);
 
48835
                DUK_ASSERT(h_name != NULL);
 
48836
 
 
48837
                if (comp_ctx->curr_func.is_strict) {
 
48838
                        if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
 
48839
                                DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError");
 
48840
                                goto error_argname;
 
48841
                        }
 
48842
                        duk_dup_top(ctx);
 
48843
                        if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
 
48844
                                DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError");
 
48845
                                goto error_argname;
 
48846
                        }
 
48847
 
 
48848
                        /* Ensure argument name is not a reserved word in current
 
48849
                         * (final) strictness.  Formal argument parsing may not
 
48850
                         * catch reserved names if strictness changes during
 
48851
                         * parsing.
 
48852
                         *
 
48853
                         * We only need to do this in strict mode because non-strict
 
48854
                         * keyword are always detected in formal argument parsing.
 
48855
                         */
 
48856
 
 
48857
                        if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
 
48858
                                goto error_argname;
 
48859
                        }
 
48860
                }
 
48861
 
 
48862
                /* overwrite any previous binding of the same name; the effect is
 
48863
                 * that last argument of a certain name wins.
 
48864
                 */
 
48865
 
 
48866
                /* only functions can have arguments */
 
48867
                DUK_ASSERT(comp_ctx->curr_func.is_function);
 
48868
                duk_push_int(ctx, i);  /* -> [ ... name index ] */
 
48869
                duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
 
48870
 
 
48871
                /* no code needs to be emitted, the regs already have values */
 
48872
        }
 
48873
 
 
48874
        /* use temp_next for tracking register allocations */
 
48875
        DUK__SETTEMP_CHECKMAX(comp_ctx, num_args);
 
48876
 
 
48877
        /*
 
48878
         *  After arguments, allocate special registers (like shuffling temps)
 
48879
         */
 
48880
 
 
48881
        if (out_stmt_value_reg) {
 
48882
                *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
 
48883
        }
 
48884
        if (comp_ctx->curr_func.needs_shuffle) {
 
48885
                int shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
 
48886
                comp_ctx->curr_func.shuffle1 = shuffle_base;
 
48887
                comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
 
48888
                comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
 
48889
                DUK_DPRINT("shuffle registers needed by function, allocated: %d %d %d",
 
48890
                           (int) comp_ctx->curr_func.shuffle1,
 
48891
                           (int) comp_ctx->curr_func.shuffle2,
 
48892
                           (int) comp_ctx->curr_func.shuffle3);
 
48893
        }
 
48894
        if (comp_ctx->curr_func.temp_next > 0x100) {
 
48895
                DUK_DPRINT("not enough 8-bit regs: temp_next=%d", (int) comp_ctx->curr_func.temp_next);
 
48896
                goto error_outofregs;
 
48897
        }
 
48898
 
 
48899
        /*
 
48900
         *  Function declarations
 
48901
         */
 
48902
 
 
48903
        num_decls = duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
 
48904
        DUK_DDDPRINT("num_decls=%d -> %!T", num_decls, duk_get_tval(ctx, comp_ctx->curr_func.decls_idx));
 
48905
        for (i = 0; i < num_decls; i += 2) {
 
48906
                int decl_type;
 
48907
                int fnum;
 
48908
 
 
48909
                duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1);  /* decl type */
 
48910
                decl_type = duk_to_int(ctx, -1);
 
48911
                fnum = decl_type >> 8;  /* FIXME: macros */
 
48912
                decl_type = decl_type & 0xff;
 
48913
                duk_pop(ctx);
 
48914
 
 
48915
                if (decl_type != DUK_DECL_TYPE_FUNC) {
 
48916
                        continue;
 
48917
                }
 
48918
 
 
48919
                duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i);  /* decl name */
 
48920
 
 
48921
                /* FIXME: spilling */
 
48922
                if (comp_ctx->curr_func.is_function) {
 
48923
                        int reg_bind;
 
48924
                        duk_dup_top(ctx);
 
48925
                        if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
 
48926
                                /* shadowed; update value */
 
48927
                                duk_dup_top(ctx);
 
48928
                                duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
 
48929
                                reg_bind = duk_to_int(ctx, -1);  /* [ ... name reg_bind ] */
 
48930
                                duk__emit_a_bc(comp_ctx, DUK_OP_CLOSURE, reg_bind, fnum);
 
48931
                        } else {
 
48932
                                /* function: always register bound */
 
48933
                                reg_bind = DUK__ALLOCTEMP(comp_ctx);
 
48934
                                duk__emit_a_bc(comp_ctx, DUK_OP_CLOSURE, reg_bind, fnum);
 
48935
                                duk_push_int(ctx, reg_bind);
 
48936
                        }
 
48937
                } else {
 
48938
                        /* Function declaration for global/eval code is emitted even
 
48939
                         * for duplicates, because of E5 Section 10.5, step 5.e of
 
48940
                         * E5.1 (special behavior for variable bound to global object).
 
48941
                         *
 
48942
                         * DECLVAR will not re-declare a variable as such, but will
 
48943
                         * update the binding value.
 
48944
                         */
 
48945
 
 
48946
                        int reg_temp = DUK__ALLOCTEMP(comp_ctx);
 
48947
                        duk_dup_top(ctx);
 
48948
                        reg_name = duk__getconst(comp_ctx);
 
48949
                        duk_push_null(ctx);
 
48950
 
 
48951
                        duk__emit_a_bc(comp_ctx, DUK_OP_CLOSURE, reg_temp, fnum);
 
48952
 
 
48953
                        declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
 
48954
                                        DUK_PROPDESC_FLAG_ENUMERABLE |
 
48955
                                        DUK_BC_DECLVAR_FLAG_FUNC_DECL;
 
48956
 
 
48957
                        if (configurable_bindings) {
 
48958
                                declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
 
48959
                        }
 
48960
 
 
48961
                        duk__emit_a_b_c(comp_ctx, DUK_OP_DECLVAR, declvar_flags /*flags*/, reg_name /*name*/, reg_temp /*value*/);
 
48962
 
 
48963
                        DUK__SETTEMP(comp_ctx, reg_temp);  /* forget temp */
 
48964
                }
 
48965
 
 
48966
                DUK_DDDPRINT("function declaration to varmap: %!T -> %!T", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
48967
 
 
48968
                duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);  /* [ ... name reg/null ] -> [ ... ] */
 
48969
        }
 
48970
 
 
48971
        /*
 
48972
         *  'arguments' binding is special; if a shadowing argument or
 
48973
         *  function declaration exists, an arguments object will
 
48974
         *  definitely not be needed, regardless of whether the identifier
 
48975
         *  'arguments' is referenced inside the function body.
 
48976
         */
 
48977
 
 
48978
        if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
 
48979
                DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
 
48980
                             "-> arguments object creation can be skipped");
 
48981
                comp_ctx->curr_func.is_arguments_shadowed = 1;
 
48982
        }
 
48983
 
 
48984
        /*
 
48985
         *  Variable declarations.
 
48986
         *
 
48987
         *  Unlike function declarations, variable declaration values don't get
 
48988
         *  assigned on entry.  If a binding of the same name already exists, just
 
48989
         *  ignore it silently.
 
48990
         */
 
48991
 
 
48992
        for (i = 0; i < num_decls; i += 2) {
 
48993
                int decl_type;
 
48994
 
 
48995
                duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1);  /* decl type */
 
48996
                decl_type = duk_to_int(ctx, -1);
 
48997
                decl_type = decl_type & 0xff;
 
48998
                duk_pop(ctx);
 
48999
 
 
49000
                if (decl_type != DUK_DECL_TYPE_VAR) {
 
49001
                        continue;
 
49002
                }
 
49003
 
 
49004
                duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i);  /* decl name */
 
49005
 
 
49006
                if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
 
49007
                        /* shadowed, ignore */
 
49008
                } else {
 
49009
                        duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i);  /* decl name */
 
49010
                        h_name = duk_get_hstring(ctx, -1);
 
49011
                        DUK_ASSERT(h_name != NULL);
 
49012
 
 
49013
                        if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
 
49014
                            !comp_ctx->curr_func.is_arguments_shadowed) {
 
49015
                                /* E5 Section steps 7-8 */
 
49016
                                DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
 
49017
                                             "but appears as a variable declaration -> treat as "
 
49018
                                             "a no-op for variable declaration purposes");
 
49019
                                duk_pop(ctx);
 
49020
                                continue;
 
49021
                        }
 
49022
 
 
49023
                        /* FIXME: spilling */
 
49024
                        if (comp_ctx->curr_func.is_function) {
 
49025
                                int reg_bind = DUK__ALLOCTEMP(comp_ctx);
 
49026
                                /* no need to init reg, it will be undefined on entry */
 
49027
                                duk_push_int(ctx, reg_bind);
 
49028
                        } else {
 
49029
                                duk_dup_top(ctx);
 
49030
                                reg_name = duk__getconst(comp_ctx);
 
49031
                                duk_push_null(ctx);
 
49032
 
 
49033
                                declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
 
49034
                                                DUK_PROPDESC_FLAG_ENUMERABLE |
 
49035
                                                DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
 
49036
                                if (configurable_bindings) {
 
49037
                                        declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
 
49038
                                }
 
49039
 
 
49040
                                duk__emit_a_b_c(comp_ctx, DUK_OP_DECLVAR, declvar_flags /*flags*/, reg_name /*name*/, 0 /*value*/);
 
49041
                        }
 
49042
 
 
49043
                        duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);  /* [ ... name reg/null ] -> [ ... ] */
 
49044
                }
 
49045
        }
 
49046
 
 
49047
        /*
 
49048
         *  Wrap up
 
49049
         */
 
49050
 
 
49051
        DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%d",
 
49052
                     duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
 
49053
                     comp_ctx->curr_func.is_arguments_shadowed);
 
49054
 
 
49055
        DUK_ASSERT_TOP(ctx, entry_top);
 
49056
        return;
 
49057
 
 
49058
 error_outofregs:
 
49059
        DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "out of regs");
 
49060
        DUK_UNREACHABLE();
 
49061
        return;
 
49062
 
 
49063
 error_argname:
 
49064
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid arg name");
 
49065
        DUK_UNREACHABLE();
 
49066
        return;
 
49067
}
 
49068
 
 
49069
/*
 
49070
 *  Parse a function-body-like expression (FunctionBody or Program
 
49071
 *  in E5 grammar) using a two-pass parse.  The productions appear
 
49072
 *  in the following contexts:
 
49073
 *
 
49074
 *    - function expression
 
49075
 *    - function statement
 
49076
 *    - function declaration
 
49077
 *    - getter in object literal
 
49078
 *    - setter in object literal
 
49079
 *    - global code
 
49080
 *    - eval code
 
49081
 *    - Function constructor body
 
49082
 *
 
49083
 *  This function only parses the statement list of the body; the argument
 
49084
 *  list and possible function name must be initialized by the caller.
 
49085
 *  For instance, for Function constructor, the argument names are originally
 
49086
 *  on the value stack.  The parsing of statements ends either at an EOF or
 
49087
 *  a closing brace; this is controlled by an input flag.
 
49088
 *
 
49089
 *  Note that there are many differences affecting parsing and even code
 
49090
 *  generation:
 
49091
 *
 
49092
 *    - Global and eval code have an implicit return value generated
 
49093
 *      by the last statement; function code does not
 
49094
 *
 
49095
 *    - Global code, eval code, and Function constructor body end in
 
49096
 *      an EOF, other bodies in a closing brace ('}')
 
49097
 *
 
49098
 *  Upon entry, 'curr_tok' is ignored and the function will pull in the
 
49099
 *  first token on its own.  Upon exit, 'curr_tok' is the terminating
 
49100
 *  token (EOF or closing brace).
 
49101
 */
 
49102
 
 
49103
static void duk__parse_func_body(duk_compiler_ctx *comp_ctx, int expect_eof, int implicit_return_value) {
 
49104
        duk_compiler_func *func = &comp_ctx->curr_func;
 
49105
        duk_hthread *thr = comp_ctx->thr;
 
49106
        duk_context *ctx = (duk_context *) thr;
 
49107
        int reg_stmt_value = -1;
 
49108
        duk_lexer_point lex_pt;
 
49109
        int temp_first;
 
49110
 
 
49111
        DUK_ASSERT(comp_ctx != NULL);
 
49112
        DUK_ASSERT(func != NULL);
 
49113
 
 
49114
        DUK__RECURSION_INCREASE(comp_ctx, thr);
 
49115
 
 
49116
        duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
 
49117
 
 
49118
        /*
 
49119
         *  Store lexer position for a later rewind
 
49120
         */
 
49121
 
 
49122
        DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
 
49123
 
 
49124
        /*
 
49125
         *  Program code (global and eval code) has an implicit return value
 
49126
         *  from the last statement value (e.g. eval("1; 2+3;") returns 3).
 
49127
         *  This is not the case with functions.  If implicit statement return
 
49128
         *  value is requested, all statements are coerced to a register
 
49129
         *  allocated here, and used in the implicit return statement below.
 
49130
         */
 
49131
 
 
49132
        /* FIXME: this is pointless here because pass 1 is throw-away */
 
49133
        if (implicit_return_value) {
 
49134
                reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
 
49135
 
 
49136
                /* If an implicit return value is needed by caller, it must be
 
49137
                 * initialized to 'undefined' because we don't know whether any
 
49138
                 * non-empty (where "empty" is a continuation type, and different
 
49139
                 * from an empty statement) statements will be executed.
 
49140
                 *
 
49141
                 * However, since 1st pass is a throwaway one, no need to emit
 
49142
                 * it here.
 
49143
                 */
 
49144
#if 0
 
49145
                duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, 0);
 
49146
#endif
 
49147
        }
 
49148
 
 
49149
        /*
 
49150
         *  First pass parsing.
 
49151
         */
 
49152
 
 
49153
        func->in_directive_prologue = 1;
 
49154
        func->in_scanning = 1;
 
49155
        func->may_direct_eval = 0;
 
49156
        func->id_access_arguments = 0;
 
49157
        func->id_access_slow = 0;
 
49158
        func->reg_stmt_value = reg_stmt_value;
 
49159
 
 
49160
        /* Need to set curr_token.t because lexing regexp mode depends on current
 
49161
         * token type.  Zero value causes "allow regexp" mode.
 
49162
         */
 
49163
        comp_ctx->curr_token.t = 0;
 
49164
        duk__advance(comp_ctx);  /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
 
49165
 
 
49166
        DUK_DDDPRINT("begin 1st pass");
 
49167
        duk__parse_stmts(comp_ctx,
 
49168
                         1,             /* allow source elements */
 
49169
                         expect_eof);   /* expect EOF instead of } */
 
49170
        DUK_DDDPRINT("end 1st pass");
 
49171
 
 
49172
        /*
 
49173
         *  Rewind lexer.
 
49174
         *
 
49175
         *  duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
 
49176
         *  literal" mode with current strictness.
 
49177
         *
 
49178
         *  curr_token line number info should be initialized for pass 2 before
 
49179
         *  generating prologue, to ensure prologue bytecode gets nice line numbers.
 
49180
         */
 
49181
 
 
49182
        DUK_DDDPRINT("rewind lexer");
 
49183
        DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
 
49184
        comp_ctx->curr_token.t = 0;  /* this is needed for regexp mode */
 
49185
        duk__advance(comp_ctx);
 
49186
 
 
49187
        /*
 
49188
         *  Reset function state and perform register allocation, which creates
 
49189
         *  'varmap' for second pass.  Function prologue for variable declarations,
 
49190
         *  binding value initializations etc is emitted as a by-product.
 
49191
         *
 
49192
         *  Strict mode restrictions for duplicate and invalid argument
 
49193
         *  names are checked here now that we know whether the function
 
49194
         *  is actually strict.  See: test-dev-strict-mode-boundary.js.
 
49195
         */
 
49196
 
 
49197
        duk__reset_func_for_pass2(comp_ctx);
 
49198
        func->in_directive_prologue = 1;
 
49199
        func->in_scanning = 0;
 
49200
 
 
49201
        /* must be able to emit code, alloc consts, etc. */
 
49202
 
 
49203
        duk__init_varmap_and_prologue_for_pass2(comp_ctx,
 
49204
                                                (implicit_return_value ? &reg_stmt_value : NULL));
 
49205
        func->reg_stmt_value = reg_stmt_value;
 
49206
 
 
49207
        temp_first = DUK__GETTEMP(comp_ctx);
 
49208
 
 
49209
        func->temp_first = temp_first;
 
49210
        func->temp_next = temp_first;
 
49211
        func->stmt_next = 0;
 
49212
        func->label_next = 0;
 
49213
 
 
49214
        /* FIXME: init or assert catch depth etc -- all values */
 
49215
        func->id_access_arguments = 0;
 
49216
        func->id_access_slow = 0;
 
49217
 
 
49218
        /*
 
49219
         *  Check function name validity now that we know strictness.
 
49220
         *  This only applies to function declarations and expressions,
 
49221
         *  not setter/getter name.
 
49222
         *
 
49223
         *  See: test-dev-strict-mode-boundary.js
 
49224
         */
 
49225
 
 
49226
        if (func->is_function && !func->is_setget && func->h_name != NULL) {
 
49227
                if (func->is_strict) {
 
49228
                        if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
 
49229
                                DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode");
 
49230
                                goto error_funcname;
 
49231
                        }
 
49232
                        if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
 
49233
                                DUK_DDDPRINT("func name is a reserved word in strict mode");
 
49234
                                goto error_funcname;
 
49235
                        }
 
49236
                } else {
 
49237
                        if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
 
49238
                            !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
 
49239
                                DUK_DDDPRINT("func name is a reserved word in non-strict mode");
 
49240
                                goto error_funcname;
 
49241
                        }
 
49242
                }
 
49243
        }
 
49244
 
 
49245
        /*
 
49246
         *  Second pass parsing.
 
49247
         */
 
49248
 
 
49249
        if (implicit_return_value) {
 
49250
                duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, 0);
 
49251
        }
 
49252
 
 
49253
        DUK_DDDPRINT("begin 2nd pass");
 
49254
        duk__parse_stmts(comp_ctx,
 
49255
                         1,             /* allow source elements */
 
49256
                         expect_eof);   /* expect EOF instead of } */
 
49257
        DUK_DDDPRINT("end 2nd pass");
 
49258
 
 
49259
        /*
 
49260
         *  Emit a final RETURN.
 
49261
         *
 
49262
         *  It would be nice to avoid emitting an unnecessary "return" opcode
 
49263
         *  if the current PC is not reachable.  However, this cannot be reliably
 
49264
         *  detected; even if the previous instruction is an unconditional jump,
 
49265
         *  there may be a previous jump which jumps to current PC (which is the
 
49266
         *  case for iteration and conditional statements, for instance).
 
49267
         */
 
49268
 
 
49269
        /* FIXME: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
 
49270
         * we could avoid the last RETURN if we could ensure there is no way to get here
 
49271
         * (directly or via a jump)
 
49272
         */
 
49273
 
 
49274
        DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);  /* fast returns are always OK here */
 
49275
        if (reg_stmt_value >= 0) {
 
49276
                duk__emit_a_b(comp_ctx,
 
49277
                              DUK_OP_RETURN,
 
49278
                              DUK_BC_RETURN_FLAG_HAVE_RETVAL | DUK_BC_RETURN_FLAG_FAST /*flags*/,
 
49279
                              reg_stmt_value /*reg*/);
 
49280
        } else {
 
49281
                duk__emit_a_b(comp_ctx,
 
49282
                              DUK_OP_RETURN,
 
49283
                              DUK_BC_RETURN_FLAG_FAST /*flags*/,
 
49284
                              0 /*reg*/);
 
49285
        }
 
49286
 
 
49287
        /*
 
49288
         *  Peephole optimize JUMP chains.
 
49289
         */
 
49290
 
 
49291
        duk__peephole_optimize_bytecode(comp_ctx);
 
49292
 
 
49293
        /*
 
49294
         *  comp_ctx->curr_func is now ready to be converted into an actual
 
49295
         *  function template.
 
49296
         */
 
49297
 
 
49298
        DUK__RECURSION_DECREASE(comp_ctx, thr);
 
49299
        return;
 
49300
 
 
49301
 error_funcname:
 
49302
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid function name");
 
49303
}
 
49304
 
 
49305
/*
 
49306
 *  Parse a function-like expression:
 
49307
 *
 
49308
 *    - function expression
 
49309
 *    - function declaration
 
49310
 *    - function statement (non-standard)
 
49311
 *    - setter/getter
 
49312
 *
 
49313
 *  Adds the function to comp_ctx->curr_func function table and returns the
 
49314
 *  function number.
 
49315
 *
 
49316
 *  On entry, curr_token points to:
 
49317
 *
 
49318
 *    - the token after 'function' for function expression/declaration/statement
 
49319
 *    - the token after 'set' or 'get' for setter/getter
 
49320
 */
 
49321
 
 
49322
/* Parse formals. */
 
49323
static void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
 
49324
        duk_hthread *thr = comp_ctx->thr;
 
49325
        duk_context *ctx = (duk_context *) thr;
 
49326
        int first = 1;
 
49327
        int n;
 
49328
 
 
49329
        for (;;) {
 
49330
                if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
 
49331
                        break;
 
49332
                }
 
49333
 
 
49334
                if (first) {
 
49335
                        /* no comma */
 
49336
                        first = 0;
 
49337
                } else {
 
49338
                        duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
 
49339
                }
 
49340
 
 
49341
                /* Note: when parsing a formal list in non-strict context, e.g.
 
49342
                 * "implements" is parsed as an identifier.  When the function is
 
49343
                 * later detected to be strict, the argument list must be rechecked
 
49344
                 * against a larger set of reserved words (that of strict mode).
 
49345
                 * This is handled by duk__parse_func_body().  Here we recognize
 
49346
                 * whatever tokens are considered reserved in current strictness
 
49347
                 * (which is not always enough).
 
49348
                 */
 
49349
 
 
49350
                if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
 
49351
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "expected identifier");
 
49352
                }
 
49353
                DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
 
49354
                DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
 
49355
                DUK_DDDPRINT("formal argument: %!O", comp_ctx->curr_token.str1);
 
49356
 
 
49357
                /* FIXME: append primitive */
 
49358
                duk_push_hstring(ctx, comp_ctx->curr_token.str1);
 
49359
                n = duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
 
49360
                duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
 
49361
 
 
49362
                duk__advance(comp_ctx);  /* eat identifier */
 
49363
        }
 
49364
}
 
49365
 
 
49366
/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
 
49367
 * correctly set up.  Assumes that curr_token is just after 'function' (or
 
49368
 * 'set'/'get' etc).
 
49369
 */
 
49370
static void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, int is_decl, int is_setget) {
 
49371
        duk_hthread *thr = comp_ctx->thr;
 
49372
        duk_context *ctx = (duk_context *) thr;
 
49373
 
 
49374
        DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
 
49375
        DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
 
49376
        DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
 
49377
        DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
 
49378
        DUK_ASSERT(comp_ctx->curr_func.is_setget == is_setget);
 
49379
        DUK_ASSERT(comp_ctx->curr_func.is_decl == is_decl);
 
49380
 
 
49381
        /*
 
49382
         *  Function name (if any)
 
49383
         *
 
49384
         *  We don't check for prohibited names here, because we don't
 
49385
         *  yet know whether the function will be strict.  Function body
 
49386
         *  parsing handles this retroactively.
 
49387
         *
 
49388
         *  For function expressions and declarations function name must
 
49389
         *  be an Identifer (excludes reserved words).  For setter/getter
 
49390
         *  it is a PropertyName which allows reserved words and also
 
49391
         *  strings and numbers (e.g. "{ get 1() { ... } }").
 
49392
         */
 
49393
 
 
49394
        if (is_setget) {
 
49395
                /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
 
49396
                if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
 
49397
                    comp_ctx->curr_token.t == DUK_TOK_STRING) {
 
49398
                        duk_push_hstring(ctx, comp_ctx->curr_token.str1);       /* keep in valstack */
 
49399
                } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
 
49400
                        duk_push_number(ctx, comp_ctx->curr_token.num);
 
49401
                        duk_to_string(ctx, -1);
 
49402
                } else {
 
49403
                        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid getter/setter name");
 
49404
                }
 
49405
                comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1);  /* borrowed reference */
 
49406
                DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
 
49407
                duk__advance(comp_ctx);
 
49408
        } else {
 
49409
                /* Function name is an Identifier (not IdentifierName), but we get
 
49410
                 * the raw name (not recognizing keywords) here and perform the name
 
49411
                 * checks only after pass 1.
 
49412
                 */
 
49413
                if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER) {
 
49414
                        duk_push_hstring(ctx, comp_ctx->curr_token.str1);       /* keep in valstack */
 
49415
                        comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1);  /* borrowed reference */
 
49416
                        DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
 
49417
                        duk__advance(comp_ctx);
 
49418
                } else {
 
49419
                        /* valstack will be unbalanced, which is OK */
 
49420
                        DUK_ASSERT(!is_setget);
 
49421
                        if (is_decl) {
 
49422
                                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "function name required");
 
49423
                        }
 
49424
                }
 
49425
        }
 
49426
 
 
49427
        DUK_DDDPRINT("function name: %!O", comp_ctx->curr_func.h_name);
 
49428
 
 
49429
        /*
 
49430
         *  Formal argument list
 
49431
         *
 
49432
         *  We don't check for prohibited names or for duplicate argument
 
49433
         *  names here, becase we don't yet know whether the function will
 
49434
         *  be strict.  Function body parsing handles this retroactively.
 
49435
         */
 
49436
 
 
49437
        duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
 
49438
 
 
49439
        duk__parse_func_formals(comp_ctx);
 
49440
 
 
49441
        DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
 
49442
        duk__advance(comp_ctx);
 
49443
 
 
49444
        /*
 
49445
         *  Parse function body
 
49446
         */
 
49447
 
 
49448
        duk__parse_func_body(comp_ctx,
 
49449
                             0,   /* expect_eof */
 
49450
                             0);  /* implicit_return_value */
 
49451
 
 
49452
        /*
 
49453
         *  Convert duk_compiler_func to a function template and add it
 
49454
         *  to the parent function table.
 
49455
         */
 
49456
 
 
49457
        duk__convert_to_func_template(comp_ctx);  /* -> [ ... func ] */
 
49458
}
 
49459
 
 
49460
/* Parse an inner function, adding the function template to the current function's
 
49461
 * function table.  Return a function number to be used by the outer function.
 
49462
 *
 
49463
 * Avoiding O(depth^2) inner function parsing is handled here.  On the first pass,
 
49464
 * compile and register the function normally into the 'funcs' array, also recording
 
49465
 * a lexer point (offset/line) to the closing brace of the function.  On the second
 
49466
 * pass, skip the function and return the same 'fnum' as on the first pass by using
 
49467
 * a running counter.
 
49468
 *
 
49469
 * An unfortunate side effect of this is that when parsing the inner function, almost
 
49470
 * nothing is known of the outer function, i.e. the inner function's scope.  We don't
 
49471
 * need that information at the moment, but it would allow some optimizations if it
 
49472
 * were used.
 
49473
 */
 
49474
static int duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, int is_decl, int is_setget) {
 
49475
        duk_hthread *thr = comp_ctx->thr;
 
49476
        duk_context *ctx = (duk_context *) thr;
 
49477
        duk_compiler_func old_func;
 
49478
        int entry_top;
 
49479
        int fnum;
 
49480
 
 
49481
        /*
 
49482
         *  On second pass, skip the function.
 
49483
         */
 
49484
 
 
49485
        if (!comp_ctx->curr_func.in_scanning) {
 
49486
                duk_lexer_point lex_pt;
 
49487
 
 
49488
                fnum = comp_ctx->curr_func.fnum_next++;
 
49489
                duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3 + 1);
 
49490
                lex_pt.offset = duk_to_int(ctx, -1);
 
49491
                duk_pop(ctx);
 
49492
                duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3 + 2);
 
49493
                lex_pt.line = duk_to_int(ctx, -1);
 
49494
                duk_pop(ctx);
 
49495
 
 
49496
                DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%d, line=%d",
 
49497
                           lex_pt.offset, lex_pt.line);
 
49498
 
 
49499
                DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
 
49500
                comp_ctx->curr_token.t = 0;  /* this is needed for regexp mode */
 
49501
                duk__advance(comp_ctx);
 
49502
                duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
 
49503
 
 
49504
                return fnum;
 
49505
        }
 
49506
 
 
49507
        /*
 
49508
         *  On first pass, perform actual parsing.  Remember valstack top on entry
 
49509
         *  to restore it later, and switch to using a new function in comp_ctx.
 
49510
         */
 
49511
 
 
49512
        entry_top = duk_get_top(ctx);
 
49513
        DUK_DDDPRINT("before func: entry_top=%d, curr_tok.start_offset=%d", entry_top, comp_ctx->curr_token.start_offset);
 
49514
 
 
49515
        DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
 
49516
 
 
49517
        DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func));
 
49518
        duk__init_func_valstack_slots(comp_ctx);
 
49519
        DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
 
49520
 
 
49521
        /* inherit initial strictness from parent */
 
49522
        comp_ctx->curr_func.is_strict = old_func.is_strict;
 
49523
 
 
49524
        comp_ctx->curr_func.is_function = 1;
 
49525
        comp_ctx->curr_func.is_eval = 0;
 
49526
        comp_ctx->curr_func.is_global = 0;
 
49527
        comp_ctx->curr_func.is_setget = is_setget;
 
49528
        comp_ctx->curr_func.is_decl = is_decl;
 
49529
 
 
49530
        /*
 
49531
         *  Parse inner function
 
49532
         */
 
49533
 
 
49534
        duk__parse_func_like_raw(comp_ctx, is_decl, is_setget);  /* pushes function template */
 
49535
 
 
49536
        /* prev_token.start_offset points to the closing brace here; when skipping
 
49537
         * we're going to reparse the closing brace to ensure semicolon insertion
 
49538
         * etc work as expected.
 
49539
         */
 
49540
        DUK_DDDPRINT("after func: prev_tok.start_offset=%d, curr_tok.start_offset=%d",
 
49541
                   comp_ctx->prev_token.start_offset, comp_ctx->curr_token.start_offset);
 
49542
        DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) '}');
 
49543
 
 
49544
        /* FIXME: append primitive */
 
49545
        DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_uint32_t) (old_func.fnum_next * 3));
 
49546
        fnum = old_func.fnum_next++;
 
49547
 
 
49548
        if (fnum >= DUK__MAX_FUNCS) {
 
49549
                DUK_ERROR(comp_ctx->thr, DUK_ERR_INTERNAL_ERROR, "out of funcs");
 
49550
        }
 
49551
 
 
49552
        (void) duk_put_prop_index(ctx, old_func.funcs_idx, fnum * 3);  /* autoincrements length */
 
49553
        duk_push_int(ctx, comp_ctx->prev_token.start_offset);
 
49554
        (void) duk_put_prop_index(ctx, old_func.funcs_idx, fnum * 3 + 1);
 
49555
        duk_push_int(ctx, comp_ctx->prev_token.start_line);
 
49556
        (void) duk_put_prop_index(ctx, old_func.funcs_idx, fnum * 3 + 2);
 
49557
 
 
49558
        /*
 
49559
         *  Cleanup: restore original function, restore valstack state.
 
49560
         */
 
49561
        
 
49562
        DUK_MEMCPY(&comp_ctx->curr_func, &old_func, sizeof(duk_compiler_func));
 
49563
        duk_set_top(ctx, entry_top);
 
49564
 
 
49565
        DUK_ASSERT_TOP(ctx, entry_top);
 
49566
 
 
49567
        return fnum;
 
49568
}
 
49569
 
 
49570
#if 0
 
49571
        /* FIXME: avoid two-pass parsing for parent functions both two passes
 
49572
         * (leading to fourfold parsing of second level functions)?  If we want
 
49573
         * do fancy parent variable lookups, the parent must be in its second
 
49574
         * pass for us to know all statically declared variables and functions.
 
49575
         * So perhaps do a single pass if parent is in its first pass, throw
 
49576
         * away the results and do two passes on parent's second pass.
 
49577
         */
 
49578
#endif
 
49579
 
 
49580
/*
 
49581
 *  Compile input string into an executable function template without
 
49582
 *  arguments.
 
49583
 *
 
49584
 *  The string is parsed as the "Program" production of Ecmascript E5.
 
49585
 *  Compilation context can be either global code or eval code (see E5
 
49586
 *  Sections 14 and 15.1.2.1).
 
49587
 *
 
49588
 *  Input stack:  [ ... sourcecode filename ]
 
49589
 *  Output stack: [ ... func_template ]
 
49590
 */
 
49591
 
 
49592
/* FIXME: source code property */
 
49593
 
 
49594
static int duk__js_compile_raw(duk_context *ctx) {
 
49595
        duk_hthread *thr = (duk_hthread *) ctx;
 
49596
        duk_hstring *h_sourcecode;
 
49597
        duk_hstring *h_filename;
 
49598
        duk__compiler_stkstate *comp_stk;
 
49599
        duk_compiler_ctx *comp_ctx;
 
49600
        duk_lexer_point *lex_pt;
 
49601
        duk_compiler_func *func;
 
49602
        int entry_top;
 
49603
        int is_strict;
 
49604
        int is_eval;
 
49605
        int is_funcexpr;
 
49606
        int flags;
 
49607
 
 
49608
        DUK_ASSERT(thr != NULL);
 
49609
 
 
49610
        /*
 
49611
         *  Arguments check
 
49612
         */
 
49613
 
 
49614
        entry_top = duk_get_top(ctx);
 
49615
        DUK_ASSERT(entry_top >= 3);
 
49616
 
 
49617
        comp_stk = (duk__compiler_stkstate *) duk_require_pointer(ctx, -1);
 
49618
        comp_ctx = &comp_stk->comp_ctx_alloc;
 
49619
        lex_pt = &comp_stk->lex_pt_alloc;
 
49620
        DUK_ASSERT(comp_ctx != NULL);
 
49621
        DUK_ASSERT(lex_pt != NULL);
 
49622
 
 
49623
        flags = comp_stk->flags;
 
49624
        is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
 
49625
        is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
 
49626
        is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
 
49627
 
 
49628
        h_sourcecode = duk_require_hstring(ctx, -3);
 
49629
        h_filename = duk_get_hstring(ctx, -2);  /* may be undefined */
 
49630
 
 
49631
        /*
 
49632
         *  Init compiler and lexer contexts
 
49633
         */
 
49634
 
 
49635
        func = &comp_ctx->curr_func;
 
49636
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
49637
        comp_ctx->thr = NULL;
 
49638
        comp_ctx->h_filename = NULL;
 
49639
        comp_ctx->prev_token.str1 = NULL;
 
49640
        comp_ctx->prev_token.str2 = NULL;
 
49641
        comp_ctx->curr_token.str1 = NULL;
 
49642
        comp_ctx->curr_token.str2 = NULL;
 
49643
#endif
 
49644
 
 
49645
        duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
 
49646
 
 
49647
        duk_push_dynamic_buffer(ctx, 0);       /* entry_top + 0 */
 
49648
        duk_push_undefined(ctx);               /* entry_top + 1 */
 
49649
        duk_push_undefined(ctx);               /* entry_top + 2 */
 
49650
        duk_push_undefined(ctx);               /* entry_top + 3 */
 
49651
        duk_push_undefined(ctx);               /* entry_top + 4 */
 
49652
 
 
49653
        comp_ctx->thr = thr;
 
49654
        comp_ctx->h_filename = h_filename;
 
49655
        comp_ctx->tok11_idx = entry_top + 1;
 
49656
        comp_ctx->tok12_idx = entry_top + 2;
 
49657
        comp_ctx->tok21_idx = entry_top + 3;
 
49658
        comp_ctx->tok22_idx = entry_top + 4;
 
49659
        comp_ctx->recursion_limit = DUK_COMPILER_RECURSION_LIMIT;
 
49660
 
 
49661
        DUK_LEXER_INITCTX(&comp_ctx->lex);   /* just zeroes/NULLs */
 
49662
        comp_ctx->lex.thr = thr;
 
49663
        comp_ctx->lex.input = DUK_HSTRING_GET_DATA(h_sourcecode);
 
49664
        comp_ctx->lex.input_length = DUK_HSTRING_GET_BYTELEN(h_sourcecode);
 
49665
        comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
 
49666
        comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
 
49667
        comp_ctx->lex.buf_idx = entry_top + 0;
 
49668
        comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
 
49669
        DUK_ASSERT(comp_ctx->lex.buf != NULL);
 
49670
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf));
 
49671
        comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
 
49672
 
 
49673
        lex_pt->offset = 0;
 
49674
        lex_pt->line = 1;
 
49675
        DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt);    /* fills window */
 
49676
 
 
49677
        /*
 
49678
         *  Initialize function state for a zero-argument function
 
49679
         */
 
49680
 
 
49681
        duk__init_func_valstack_slots(comp_ctx);
 
49682
        DUK_ASSERT(func->num_formals == 0);
 
49683
 
 
49684
        if (is_funcexpr) {
 
49685
                /* funcexpr is now used for Function constructor, anonymous */
 
49686
        } else {
 
49687
                duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
 
49688
                                                        DUK_STRIDX_GLOBAL));
 
49689
                func->h_name = duk_get_hstring(ctx, -1);
 
49690
        }
 
49691
 
 
49692
        /*
 
49693
         *  Parse a function body or a function-like expression, depending
 
49694
         *  on flags.
 
49695
         */
 
49696
 
 
49697
        func->is_strict = is_strict;
 
49698
        func->is_setget = 0;
 
49699
        func->is_decl = 0;
 
49700
 
 
49701
        if (is_funcexpr) {
 
49702
                func->is_function = 1;
 
49703
                func->is_eval = 0;
 
49704
                func->is_global = 0;
 
49705
 
 
49706
                duk__advance(comp_ctx);  /* init 'curr_token' */
 
49707
                duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
 
49708
                (void) duk__parse_func_like_raw(comp_ctx,
 
49709
                                                0,      /* is_decl */
 
49710
                                                0);     /* is_setget */
 
49711
        } else {
 
49712
                func->is_function = 0;
 
49713
                func->is_eval = is_eval;
 
49714
                func->is_global = !is_eval;
 
49715
 
 
49716
                duk__parse_func_body(comp_ctx,
 
49717
                                     1,             /* expect_eof */
 
49718
                                     1);            /* implicit_return_value */
 
49719
        }
 
49720
 
 
49721
        /*
 
49722
         *  Convert duk_compiler_func to a function template
 
49723
         */
 
49724
 
 
49725
        duk__convert_to_func_template(comp_ctx);
 
49726
 
 
49727
        /*
 
49728
         *  Wrapping duk_safe_call() will mangle the stack, just return stack top
 
49729
         */
 
49730
 
 
49731
        /* [ ... sourcecode filename (temps) func ] */
 
49732
 
 
49733
        return 1;
 
49734
}
 
49735
 
 
49736
void duk_js_compile(duk_hthread *thr, int flags) {
 
49737
        duk_context *ctx = (duk_context *) thr;
 
49738
        duk__compiler_stkstate comp_stk;
 
49739
 
 
49740
        /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
 
49741
         * is a bit heavy at the moment.  The wrapper compiles to ~180 bytes on x64.
 
49742
         * Alternatives would be nice.
 
49743
         */
 
49744
 
 
49745
        DUK_MEMZERO(&comp_stk, sizeof(comp_stk));
 
49746
        comp_stk.flags = flags;
 
49747
        duk_push_pointer(ctx, (void *) &comp_stk);
 
49748
 
 
49749
        if (duk_safe_call(ctx, duk__js_compile_raw, 3 /*nargs*/, 1 /*nret*/) != DUK_EXEC_SUCCESS) {
 
49750
                /* This now adds a line number to -any- error thrown during compilation.
 
49751
                 * Usually compilation errors are SyntaxErrors but they could also be
 
49752
                 * out-of-memory errors and the like.
 
49753
                 */
 
49754
 
 
49755
                DUK_DDDPRINT("compile error, before adding line info: %!T", duk_get_tval(ctx, -1));
 
49756
                if (duk_is_object(ctx, -1)) {
 
49757
                        if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
 
49758
                                duk_push_sprintf(ctx, " (line %d)", (int) comp_stk.comp_ctx_alloc.curr_token.start_line);
 
49759
                                duk_concat(ctx, 2);
 
49760
                                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
 
49761
                        } else {
 
49762
                                duk_pop(ctx);
 
49763
                        }
 
49764
                }
 
49765
                DUK_DDDPRINT("compile error, after adding line info: %!T", duk_get_tval(ctx, -1));
 
49766
                duk_throw(ctx);
 
49767
        }
 
49768
}
 
49769
#line 1 "duk_js_executor.c"
 
49770
/*
 
49771
 *  Ecmascript bytecode executor.
 
49772
 */
 
49773
 
 
49774
/* include removed: duk_internal.h */
 
49775
 
 
49776
/*
 
49777
 *  Local forward declarations
 
49778
 */
 
49779
 
 
49780
static void duk__reconfig_valstack(duk_hthread *thr, int act_idx, int retval_count);
 
49781
 
 
49782
/*
 
49783
 *  Helper for finding the final non-bound function in a "bound function" chain.
 
49784
 */
 
49785
 
 
49786
/* FIXME: overlap with other helpers, rework */
 
49787
static duk_hobject *duk__find_nonbound_function(duk_hthread *thr, duk_hobject *func) {
 
49788
        duk_context *ctx = (duk_context *) thr;
 
49789
        duk_uint32_t sanity;
 
49790
 
 
49791
        DUK_ASSERT(thr != NULL);
 
49792
        DUK_ASSERT(func != NULL);
 
49793
        DUK_ASSERT(DUK_HOBJECT_HAS_BOUND(func));
 
49794
 
 
49795
        sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
 
49796
        do {    
 
49797
                if (!DUK_HOBJECT_HAS_BOUND(func)) {
 
49798
                        break;
 
49799
                }
 
49800
 
 
49801
                duk_push_hobject(ctx, func);
 
49802
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
 
49803
                func = duk_require_hobject(ctx, -1);
 
49804
                duk_pop_2(ctx);
 
49805
        } while (--sanity > 0);
 
49806
 
 
49807
        if (sanity == 0) {
 
49808
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "function call bound chain sanity exceeded");
 
49809
        }
 
49810
 
 
49811
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
49812
        DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) || DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
 
49813
 
 
49814
        return func;
 
49815
}
 
49816
 
 
49817
/*
 
49818
 *  Arithmetic, binary, and logical helpers.
 
49819
 *
 
49820
 *  Note: there is no opcode for logical AND or logical OR; this is on
 
49821
 *  purpose, because the evalution order semantics for them make such
 
49822
 *  opcodes pretty pointless (short circuiting means they are most
 
49823
 *  comfortably implemented as jumps).  However, a logical NOT opcode
 
49824
 *  is useful.
 
49825
 *
 
49826
 *  Note: careful with duk_tval pointers here: they are potentially
 
49827
 *  invalidated by any DECREF and almost any API call.
 
49828
 */
 
49829
 
 
49830
static double duk__compute_mod(double d1, double d2) {
 
49831
        /*
 
49832
         *  Ecmascript modulus ('%') does not match IEEE 754 "remainder"
 
49833
         *  operation (implemented by remainder() in C99) but does seem
 
49834
         *  to match ANSI C fmod().
 
49835
         *
 
49836
         *  Compare E5 Section 11.5.3 and "man fmod".
 
49837
         */
 
49838
 
 
49839
        return DUK_FMOD(d1, d2);
 
49840
}
 
49841
 
 
49842
static void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, int idx_z) {
 
49843
        /*
 
49844
         *  Addition operator is different from other arithmetic
 
49845
         *  operations in that it also provides string concatenation.
 
49846
         *  Hence it is implemented separately.
 
49847
         *
 
49848
         *  There is a fast path for number addition.  Other cases go
 
49849
         *  through potentially multiple coercions as described in the
 
49850
         *  E5 specification.  It may be possible to reduce the number
 
49851
         *  of coercions, but this must be done carefully to preserve
 
49852
         *  the exact semantics.
 
49853
         *
 
49854
         *  E5 Section 11.6.1.
 
49855
         *
 
49856
         *  Custom types also have special behavior implemented here.
 
49857
         */
 
49858
 
 
49859
        duk_context *ctx = (duk_context *) thr;
 
49860
        duk_double_union du;
 
49861
 
 
49862
        DUK_ASSERT(thr != NULL);
 
49863
        DUK_ASSERT(ctx != NULL);
 
49864
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
49865
        DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
 
49866
        DUK_ASSERT(idx_z >= 0 && idx_z < duk_get_top(ctx));
 
49867
 
 
49868
        /*
 
49869
         *  Fast paths
 
49870
         */
 
49871
 
 
49872
        if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
 
49873
                duk_tval tv_tmp;
 
49874
                duk_tval *tv_z;
 
49875
 
 
49876
                du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
 
49877
                DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
49878
                DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
 
49879
 
 
49880
                tv_z = &thr->valstack_bottom[idx_z];
 
49881
                DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
49882
                DUK_TVAL_SET_NUMBER(tv_z, du.d);
 
49883
                DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_z));  /* no need to incref */
 
49884
                DUK_TVAL_DECREF(thr, &tv_tmp);   /* side effects */
 
49885
                return;
 
49886
        }
 
49887
 
 
49888
        /*
 
49889
         *  Slow path: potentially requires function calls for coercion
 
49890
         */
 
49891
 
 
49892
        duk_push_tval(ctx, tv_x);
 
49893
        duk_push_tval(ctx, tv_y);
 
49894
        duk_to_primitive(ctx, -2, DUK_HINT_NONE);  /* side effects -> don't use tv_x, tv_y after */
 
49895
        duk_to_primitive(ctx, -1, DUK_HINT_NONE);
 
49896
 
 
49897
        /* As a first approximation, buffer values are coerced to strings
 
49898
         * for addition.  This means that adding two buffers currently
 
49899
         * results in a string.
 
49900
         */
 
49901
        if (duk_check_type_mask(ctx, -2, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER) ||
 
49902
            duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER)) {
 
49903
                duk_to_string(ctx, -2);
 
49904
                duk_to_string(ctx, -1);
 
49905
                duk_concat(ctx, 2);  /* [... s1 s2] -> [... s1+s2] */
 
49906
                duk_replace(ctx, idx_z);  /* side effects */
 
49907
        } else {
 
49908
                double d1, d2;
 
49909
 
 
49910
                d1 = duk_to_number(ctx, -2);
 
49911
                d2 = duk_to_number(ctx, -1);
 
49912
                DUK_ASSERT(duk_is_number(ctx, -2));
 
49913
                DUK_ASSERT(duk_is_number(ctx, -1));
 
49914
                DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
 
49915
                DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
 
49916
 
 
49917
                du.d = d1 + d2;
 
49918
                DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
49919
                DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
 
49920
 
 
49921
                duk_pop_2(ctx);
 
49922
                duk_push_number(ctx, du.d);
 
49923
                duk_replace(ctx, idx_z);  /* side effects */
 
49924
        }
 
49925
}
 
49926
 
 
49927
static void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, int idx_z, int opcode) {
 
49928
        /*
 
49929
         *  Arithmetic operations other than '+' have number-only semantics
 
49930
         *  and are implemented here.  The separate switch-case here means a
 
49931
         *  "double dispatch" of the arithmetic opcode, but saves code space.
 
49932
         *
 
49933
         *  E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
 
49934
         */
 
49935
 
 
49936
        duk_context *ctx = (duk_context *) thr;
 
49937
        duk_tval tv_tmp;
 
49938
        duk_tval *tv_z;
 
49939
        double d1, d2;
 
49940
        duk_double_union du;
 
49941
 
 
49942
        DUK_ASSERT(thr != NULL);
 
49943
        DUK_ASSERT(ctx != NULL);
 
49944
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
49945
        DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
 
49946
        DUK_ASSERT(idx_z >= 0 && idx_z < duk_get_top(ctx));
 
49947
 
 
49948
        if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
 
49949
                /* fast path */
 
49950
                d1 = DUK_TVAL_GET_NUMBER(tv_x);
 
49951
                d2 = DUK_TVAL_GET_NUMBER(tv_y);
 
49952
        } else {
 
49953
                duk_push_tval(ctx, tv_x);
 
49954
                duk_push_tval(ctx, tv_y);
 
49955
                d1 = duk_to_number(ctx, -2);  /* side effects */
 
49956
                d2 = duk_to_number(ctx, -1);
 
49957
                DUK_ASSERT(duk_is_number(ctx, -2));
 
49958
                DUK_ASSERT(duk_is_number(ctx, -1));
 
49959
                DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
 
49960
                DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
 
49961
                duk_pop_2(ctx);
 
49962
        }
 
49963
 
 
49964
        switch (opcode) {
 
49965
        case DUK_OP_SUB: {
 
49966
                du.d = d1 - d2;
 
49967
                break;
 
49968
        }
 
49969
        case DUK_OP_MUL: {
 
49970
                du.d = d1 * d2;
 
49971
                break;
 
49972
        }
 
49973
        case DUK_OP_DIV: {
 
49974
                du.d = d1 / d2;
 
49975
                break;
 
49976
        }
 
49977
        case DUK_OP_MOD: {
 
49978
                du.d = duk__compute_mod(d1, d2);
 
49979
                break;
 
49980
        }
 
49981
        default: {
 
49982
                du.d = DUK_DOUBLE_NAN;  /* should not happen */
 
49983
                break;
 
49984
        }
 
49985
        }
 
49986
 
 
49987
        /* important to use normalized NaN with 8-byte tagged types */
 
49988
        DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
49989
        DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
 
49990
        
 
49991
        tv_z = &thr->valstack_bottom[idx_z];
 
49992
        DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
49993
        DUK_TVAL_SET_NUMBER(tv_z, du.d);
 
49994
        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_z));  /* no need to incref */
 
49995
        DUK_TVAL_DECREF(thr, &tv_tmp);   /* side effects */
 
49996
}
 
49997
 
 
49998
static void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, int idx_z, int opcode) {
 
49999
        /*
 
50000
         *  Binary bitwise operations use different coercions (ToInt32, ToUint32)
 
50001
         *  depending on the operation.  We coerce the arguments first using
 
50002
         *  ToInt32(), and then cast to an 32-bit value if necessary.  Note that
 
50003
         *  such casts must be correct even if there is no native 32-bit type
 
50004
         *  (e.g., duk_int32_t and duk_uint32_t are 64-bit).
 
50005
         *
 
50006
         *  E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
 
50007
         */
 
50008
 
 
50009
        duk_context *ctx = (duk_context *) thr;
 
50010
        duk_tval tv_tmp;
 
50011
        duk_tval *tv_z;
 
50012
        duk_int32_t i1, i2;
 
50013
        double val;
 
50014
 
 
50015
        DUK_ASSERT(thr != NULL);
 
50016
        DUK_ASSERT(ctx != NULL);
 
50017
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
50018
        DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
 
50019
        DUK_ASSERT(idx_z >= 0 && idx_z < duk_get_top(ctx));
 
50020
 
 
50021
        duk_push_tval(ctx, tv_x);
 
50022
        duk_push_tval(ctx, tv_y);
 
50023
        i1 = duk_to_int32(ctx, -2);
 
50024
        i2 = duk_to_int32(ctx, -1);
 
50025
        duk_pop_2(ctx);
 
50026
 
 
50027
        switch (opcode) {
 
50028
        case DUK_OP_BAND: {
 
50029
                val = (double) (i1 & i2);
 
50030
                break;
 
50031
        }
 
50032
        case DUK_OP_BOR: {
 
50033
                val = (double) (i1 | i2);
 
50034
                break;
 
50035
        }
 
50036
        case DUK_OP_BXOR: {
 
50037
                val = (double) (i1 ^ i2);
 
50038
                break;
 
50039
        }
 
50040
        case DUK_OP_BASL: {
 
50041
                /* Signed shift, named "arithmetic" (asl) because the result
 
50042
                 * is signed, e.g. 4294967295 << 1 -> -2.  Note that result
 
50043
                 * must be masked.
 
50044
                 */
 
50045
 
 
50046
                duk_uint32_t u2;
 
50047
                duk_int32_t i3;
 
50048
 
 
50049
                u2 = ((duk_uint32_t) i2) & 0xffffffffU;
 
50050
                i3 = i1 << (u2 & 0x1f);                     /* E5 Section 11.7.1, steps 7 and 8 */
 
50051
                i3 = i3 & ((duk_int32_t) 0xffffffffU);      /* Note: left shift, should mask */
 
50052
                val = (double) i3;
 
50053
                break;
 
50054
        }
 
50055
        case DUK_OP_BASR: {
 
50056
                /* signed shift */
 
50057
 
 
50058
                duk_uint32_t u2;
 
50059
 
 
50060
                u2 = ((duk_uint32_t) i2) & 0xffffffffU;
 
50061
                val = (double) (i1 >> (u2 & 0x1f));     /* E5 Section 11.7.2, steps 7 and 8 */
 
50062
                break;
 
50063
        }
 
50064
        case DUK_OP_BLSR: {
 
50065
                /* unsigned shift */
 
50066
 
 
50067
                duk_uint32_t u1;
 
50068
                duk_uint32_t u2;
 
50069
 
 
50070
                u1 = ((duk_uint32_t) i1) & 0xffffffffU;
 
50071
                u2 = ((duk_uint32_t) i2) & 0xffffffffU;
 
50072
 
 
50073
                val = (double) (u1 >> (u2 & 0x1f));     /* E5 Section 11.7.2, steps 7 and 8 */
 
50074
                break;
 
50075
        }
 
50076
        default: {
 
50077
                val = (double) 0;  /* should not happen */
 
50078
                break;
 
50079
        }
 
50080
        }
 
50081
 
 
50082
        DUK_ASSERT(!DUK_ISNAN(val));            /* 'val' is never NaN, so no need to normalize */
 
50083
        DUK_ASSERT_DOUBLE_IS_NORMALIZED(val);   /* always normalized */
 
50084
 
 
50085
        tv_z = &thr->valstack_bottom[idx_z];
 
50086
        DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
50087
        DUK_TVAL_SET_NUMBER(tv_z, val);
 
50088
        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_z));  /* no need to incref */
 
50089
        DUK_TVAL_DECREF(thr, &tv_tmp);   /* side effects */
 
50090
}
 
50091
 
 
50092
static void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, int idx_z, int opcode) {
 
50093
        /*
 
50094
         *  Arithmetic operations other than '+' have number-only semantics
 
50095
         *  and are implemented here.  The separate switch-case here means a
 
50096
         *  "double dispatch" of the arithmetic opcode, but saves code space.
 
50097
         *
 
50098
         *  E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
 
50099
         */
 
50100
 
 
50101
        duk_context *ctx = (duk_context *) thr;
 
50102
        duk_tval tv_tmp;
 
50103
        duk_tval *tv_z;
 
50104
        double d1;
 
50105
        duk_double_union du;
 
50106
 
 
50107
        DUK_ASSERT(thr != NULL);
 
50108
        DUK_ASSERT(ctx != NULL);
 
50109
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
50110
        DUK_ASSERT(idx_z >= 0 && idx_z < duk_get_top(ctx));
 
50111
 
 
50112
        if (DUK_TVAL_IS_NUMBER(tv_x)) {
 
50113
                /* fast path */
 
50114
                d1 = DUK_TVAL_GET_NUMBER(tv_x);
 
50115
        } else {
 
50116
                duk_push_tval(ctx, tv_x);
 
50117
                d1 = duk_to_number(ctx, -1);  /* side effects */
 
50118
                DUK_ASSERT(duk_is_number(ctx, -1));
 
50119
                DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
 
50120
                duk_pop(ctx);
 
50121
        }
 
50122
 
 
50123
        switch (opcode) {
 
50124
        case DUK_EXTRAOP_UNM: {
 
50125
                du.d = -d1;
 
50126
                break;
 
50127
        }
 
50128
        case DUK_EXTRAOP_UNP: {
 
50129
                du.d = d1;
 
50130
                break;
 
50131
        }
 
50132
        case DUK_EXTRAOP_INC: {
 
50133
                du.d = d1 + 1.0;
 
50134
                break;
 
50135
        }
 
50136
        case DUK_EXTRAOP_DEC: {
 
50137
                du.d = d1 - 1.0;
 
50138
                break;
 
50139
        }
 
50140
        default: {
 
50141
                du.d = DUK_DOUBLE_NAN;  /* should not happen */
 
50142
                break;
 
50143
        }
 
50144
        }
 
50145
 
 
50146
        DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
 
50147
        DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
 
50148
 
 
50149
        tv_z = &thr->valstack_bottom[idx_z];
 
50150
        DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
50151
        DUK_TVAL_SET_NUMBER(tv_z, du.d);
 
50152
        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_z));  /* no need to incref */
 
50153
        DUK_TVAL_DECREF(thr, &tv_tmp);   /* side effects */
 
50154
}
 
50155
 
 
50156
static void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, int idx_z) {
 
50157
        /*
 
50158
         *  E5 Section 11.4.8
 
50159
         */
 
50160
 
 
50161
        duk_context *ctx = (duk_context *) thr;
 
50162
        duk_tval tv_tmp;
 
50163
        duk_tval *tv_z;
 
50164
        duk_int32_t i1, i2;
 
50165
        double val;
 
50166
 
 
50167
        DUK_ASSERT(thr != NULL);
 
50168
        DUK_ASSERT(ctx != NULL);
 
50169
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
50170
        DUK_ASSERT(idx_z >= 0 && idx_z < duk_get_top(ctx));
 
50171
 
 
50172
        duk_push_tval(ctx, tv_x);
 
50173
        i1 = duk_to_int32(ctx, -1);
 
50174
        duk_pop(ctx);
 
50175
 
 
50176
        i2 = ~i1;
 
50177
        val = (double) i2;
 
50178
 
 
50179
        DUK_ASSERT(!DUK_ISNAN(val));            /* 'val' is never NaN, so no need to normalize */
 
50180
        DUK_ASSERT_DOUBLE_IS_NORMALIZED(val);   /* always normalized */
 
50181
 
 
50182
        tv_z = &thr->valstack_bottom[idx_z];
 
50183
        DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
50184
        DUK_TVAL_SET_NUMBER(tv_z, val);
 
50185
        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_z));  /* no need to incref */
 
50186
        DUK_TVAL_DECREF(thr, &tv_tmp);   /* side effects */
 
50187
}
 
50188
 
 
50189
static void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_z) {
 
50190
        /*
 
50191
         *  E5 Section 11.4.9
 
50192
         */
 
50193
 
 
50194
        duk_tval tv_tmp;
 
50195
        int res;
 
50196
 
 
50197
        DUK_ASSERT(thr != NULL);
 
50198
        DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
 
50199
        DUK_ASSERT(tv_z != NULL);  /* reg */
 
50200
 
 
50201
        /* ToBoolean() does not require any operations with side effects so
 
50202
         * we can do it efficiently.  For footprint it would be better to use
 
50203
         * duk_js_toboolean() and then push+replace to the result slot.
 
50204
         */
 
50205
        res = duk_js_toboolean(tv_x);  /* does not modify tv_x */
 
50206
        DUK_ASSERT(res == 0 || res == 1);
 
50207
        res ^= 1;
 
50208
        DUK_TVAL_SET_TVAL(&tv_tmp, tv_z);
 
50209
        DUK_TVAL_SET_BOOLEAN(tv_z, res);  /* no need to incref */
 
50210
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50211
}
 
50212
 
 
50213
/*
 
50214
 *  Longjmp handler for the bytecode executor (and a bunch of static
 
50215
 *  helpers for it).
 
50216
 *
 
50217
 *  Any type of longjmp() can be caught here, including intra-function
 
50218
 *  longjmp()s like 'break', 'continue', (slow) 'return', 'yield', etc.
 
50219
 *
 
50220
 *  Error policy: should not ordinarily throw errors.  Errors thrown
 
50221
 *  will bubble outwards.
 
50222
 *
 
50223
 *  Returns:
 
50224
 *    0   restart execution
 
50225
 *    1   bytecode executor finished
 
50226
 *    2   rethrow longjmp
 
50227
 */
 
50228
 
 
50229
/* FIXME: duk_api operations for cross-thread reg manipulation? */
 
50230
/* FIXME: post-condition: value stack must be correct; for ecmascript functions, clamped to 'nregs' */
 
50231
 
 
50232
#define DUK__LONGJMP_RESTART   0  /* state updated, restart bytecode execution */
 
50233
#define DUK__LONGJMP_FINISHED  1  /* exit bytecode executor with return value */
 
50234
#define DUK__LONGJMP_RETHROW   2  /* exit bytecode executor by rethrowing an error to caller */
 
50235
 
 
50236
/* only called when act_idx points to an Ecmascript function */
 
50237
static void duk__reconfig_valstack(duk_hthread *thr, int act_idx, int retval_count) {
 
50238
        duk_hcompiledfunction *h_func;
 
50239
 
 
50240
        DUK_ASSERT(thr != NULL);
 
50241
        DUK_ASSERT(act_idx >= 0);
 
50242
        DUK_ASSERT(thr->callstack[act_idx].func != NULL);
 
50243
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(thr->callstack[act_idx].func));
 
50244
        DUK_ASSERT(thr->callstack[act_idx].idx_retval >= 0);
 
50245
 
 
50246
        thr->valstack_bottom = thr->valstack + thr->callstack[act_idx].idx_bottom;
 
50247
 
 
50248
        /* clamp so that retval is at the top (retval_count == 1) or register just before
 
50249
         * intended retval is at the top (retval_count == 0, happens e.g. with 'finally').
 
50250
         */
 
50251
        duk_set_top((duk_context *) thr, 
 
50252
                    thr->callstack[act_idx].idx_retval -
 
50253
                    thr->callstack[act_idx].idx_bottom +
 
50254
                    retval_count);
 
50255
 
 
50256
        /*
 
50257
         *  When returning to an Ecmascript function, extend the valstack
 
50258
         *  top to 'nregs' always.
 
50259
         */
 
50260
 
 
50261
        h_func = (duk_hcompiledfunction *) thr->callstack[act_idx].func;
 
50262
 
 
50263
        duk_require_valstack_resize((duk_context *) thr,
 
50264
                                    (thr->valstack_bottom - thr->valstack) +          /* bottom of current func */
 
50265
                                        h_func->nregs +                               /* reg count */
 
50266
                                        DUK_VALSTACK_INTERNAL_EXTRA,                  /* + spare */
 
50267
                                    1);                                               /* allow_shrink */
 
50268
 
 
50269
        duk_set_top((duk_context *) thr, h_func->nregs);
 
50270
}
 
50271
 
 
50272
static void duk__handle_catch_or_finally(duk_hthread *thr, int cat_idx, int is_finally) {
 
50273
        duk_context *ctx = (duk_context *) thr;
 
50274
        duk_tval tv_tmp;
 
50275
        duk_tval *tv1;
 
50276
 
 
50277
        DUK_DDDPRINT("handling catch/finally, cat_idx=%d, is_finally=%d",
 
50278
                     cat_idx, is_finally);
 
50279
 
 
50280
        /*
 
50281
         *  Set caught value and longjmp type to catcher regs.
 
50282
         */
 
50283
 
 
50284
        DUK_DDDPRINT("writing catch registers: idx_base=%d -> %!T, idx_base+1=%d -> %!T",
 
50285
                     thr->catchstack[cat_idx].idx_base,
 
50286
                     &thr->heap->lj.value1,
 
50287
                     thr->catchstack[cat_idx].idx_base + 1,
 
50288
                     &thr->heap->lj.value2);
 
50289
 
 
50290
        tv1 = &thr->valstack[thr->catchstack[cat_idx].idx_base];
 
50291
        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
50292
        DUK_TVAL_SET_TVAL(tv1, &thr->heap->lj.value1);
 
50293
        DUK_TVAL_INCREF(thr, tv1);
 
50294
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50295
 
 
50296
        tv1 = &thr->valstack[thr->catchstack[cat_idx].idx_base + 1];
 
50297
        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
50298
        DUK_TVAL_SET_NUMBER(tv1, (double) thr->heap->lj.type);
 
50299
        DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv1));   /* no need to incref */
 
50300
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50301
 
 
50302
        /*
 
50303
         *  Unwind catchstack and callstack.
 
50304
         *
 
50305
         *  The 'cat_idx' catcher is always kept, even when executing finally.
 
50306
         */
 
50307
 
 
50308
        duk_hthread_catchstack_unwind(thr, cat_idx + 1);
 
50309
        duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
 
50310
 
 
50311
        /*
 
50312
         *  Reconfigure valstack to 'nregs' (this is always the case for
 
50313
         *  Ecmascript functions).
 
50314
         */
 
50315
 
 
50316
        DUK_ASSERT(thr->callstack_top >= 1);
 
50317
        DUK_ASSERT(thr->callstack[thr->callstack_top - 1].func != NULL);
 
50318
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(thr->callstack[thr->callstack_top - 1].func));
 
50319
 
 
50320
        thr->valstack_bottom = thr->valstack + (thr->callstack + thr->callstack_top - 1)->idx_bottom;
 
50321
        duk_set_top((duk_context *) thr, ((duk_hcompiledfunction *) (thr->callstack + thr->callstack_top - 1)->func)->nregs);
 
50322
 
 
50323
        /*
 
50324
         *  Reset PC: resume execution from catch or finally jump slot.
 
50325
         */
 
50326
 
 
50327
        (thr->callstack + thr->callstack_top - 1)->pc =
 
50328
                thr->catchstack[cat_idx].pc_base + (is_finally ? 1 : 0);
 
50329
 
 
50330
        /*
 
50331
         *  If entering a 'catch' block which requires an automatic
 
50332
         *  catch variable binding, create the lexical environment.
 
50333
         *
 
50334
         *  The binding is mutable (= writable) but not deletable.
 
50335
         *  Step 4 for the catch production in E5 Section 12.14;
 
50336
         *  no value is given for CreateMutableBinding 'D' argument,
 
50337
         *  which implies the binding is not deletable.
 
50338
         */
 
50339
 
 
50340
        if (!is_finally && DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
 
50341
                duk_activation *act;
 
50342
                duk_hobject *new_env;
 
50343
                duk_hobject *act_lex_env;
 
50344
 
 
50345
                DUK_DDDPRINT("catcher has an automatic catch binding");
 
50346
 
 
50347
                /* Note: 'act' is dangerous here because it may get invalidate at many
 
50348
                 * points, so we re-lookup it multiple times.
 
50349
                 */
 
50350
                DUK_ASSERT(thr->callstack_top >= 1);
 
50351
                act = thr->callstack + thr->callstack_top - 1;
 
50352
 
 
50353
                if (act->lex_env == NULL) {
 
50354
                        DUK_ASSERT(act->var_env == NULL);
 
50355
                        DUK_DDDPRINT("delayed environment initialization");
 
50356
 
 
50357
                        /* this may have side effects, so re-lookup act */
 
50358
                        duk_js_init_activation_environment_records_delayed(thr, act);
 
50359
                        act = thr->callstack + thr->callstack_top - 1;
 
50360
                }
 
50361
                DUK_ASSERT(act->lex_env != NULL);
 
50362
                DUK_ASSERT(act->var_env != NULL);
 
50363
                DUK_ASSERT(act->func != NULL);
 
50364
                DUK_UNREF(act);  /* unreferenced without assertions */
 
50365
 
 
50366
                act = thr->callstack + thr->callstack_top - 1;
 
50367
                act_lex_env = act->lex_env;
 
50368
                act = NULL;  /* invalidated */
 
50369
 
 
50370
                (void) duk_push_object_helper_proto(ctx,
 
50371
                                                    DUK_HOBJECT_FLAG_EXTENSIBLE |
 
50372
                                                    DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
 
50373
                                                    act_lex_env);
 
50374
                new_env = duk_require_hobject(ctx, -1);
 
50375
                DUK_ASSERT(new_env != NULL);
 
50376
                DUK_DDDPRINT("new_env allocated: %!iO", new_env);
 
50377
 
 
50378
                /* Note: currently the catch binding is handled without a register
 
50379
                 * binding because we don't support dynamic register bindings (they
 
50380
                 * must be fixed for an entire function).  So, there is no need to
 
50381
                 * record regbases etc.
 
50382
                 */
 
50383
 
 
50384
                DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
 
50385
                duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
 
50386
                duk_push_tval(ctx, &thr->heap->lj.value1);
 
50387
                duk_def_prop(ctx, -3, DUK_PROPDESC_FLAGS_W);  /* writable, not configurable */
 
50388
 
 
50389
                act = thr->callstack + thr->callstack_top - 1;
 
50390
                act->lex_env = new_env;
 
50391
                DUK_HOBJECT_INCREF(thr, new_env);  /* reachable through activation */
 
50392
 
 
50393
                DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
 
50394
 
 
50395
                duk_pop(ctx);
 
50396
 
 
50397
                DUK_DDDPRINT("new_env finished: %!iO", new_env);
 
50398
        }
 
50399
 
 
50400
        if (is_finally) {
 
50401
                DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
 
50402
        } else {
 
50403
                DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
 
50404
        }
 
50405
}
 
50406
 
 
50407
static void duk__handle_label(duk_hthread *thr, int cat_idx) {
 
50408
        /* no callstack changes, no value stack changes */
 
50409
 
 
50410
        /* +0 = break, +1 = continue */
 
50411
        (thr->callstack + thr->callstack_top - 1)->pc =
 
50412
                thr->catchstack[cat_idx].pc_base + (thr->heap->lj.type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
 
50413
 
 
50414
        duk_hthread_catchstack_unwind(thr, cat_idx + 1);  /* keep label catcher */
 
50415
        /* no need to unwind callstack */
 
50416
}
 
50417
 
 
50418
/* Note: called for DUK_LJ_TYPE_YIELD and for DUK_LJ_TYPE_RETURN, when a
 
50419
 * return terminates a thread and yields to the resumer.
 
50420
 */
 
50421
static void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, int act_idx) {
 
50422
        duk_tval tv_tmp;
 
50423
        duk_tval *tv1;
 
50424
 
 
50425
        /* this may also be called for DUK_LJ_TYPE_RETURN; this is OK as long as
 
50426
         * lj.value1 is correct.
 
50427
         */
 
50428
 
 
50429
        DUK_ASSERT(resumer->callstack[act_idx].func != NULL);
 
50430
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(resumer->callstack[act_idx].func));  /* resume caller must be an ecmascript func */
 
50431
 
 
50432
        DUK_DDDPRINT("resume idx_retval is %d", resumer->callstack[act_idx].idx_retval);
 
50433
 
 
50434
        tv1 = &resumer->valstack[resumer->callstack[act_idx].idx_retval];  /* return value from Duktape.Thread.resume() */
 
50435
        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
50436
        DUK_TVAL_SET_TVAL(tv1, &thr->heap->lj.value1);
 
50437
        DUK_TVAL_INCREF(thr, tv1);
 
50438
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50439
 
 
50440
        duk_hthread_callstack_unwind(resumer, act_idx + 1);  /* unwind to 'resume' caller */
 
50441
 
 
50442
        /* no need to unwind catchstack */
 
50443
        duk__reconfig_valstack(resumer, act_idx, 1);  /* 1 = have retval */
 
50444
 
 
50445
        /* caller must change active thread, and set thr->resumer to NULL */
 
50446
}
 
50447
 
 
50448
static int duk__handle_longjmp(duk_hthread *thr,
 
50449
                               duk_hthread *entry_thread,
 
50450
                               duk_size_t entry_callstack_top) {
 
50451
        duk_tval tv_tmp;
 
50452
        duk_size_t entry_callstack_index;
 
50453
        int retval = DUK__LONGJMP_RESTART;
 
50454
 
 
50455
        DUK_ASSERT(thr != NULL);
 
50456
        DUK_ASSERT(entry_thread != NULL);
 
50457
        DUK_ASSERT(entry_callstack_top > 0);  /* guarantees entry_callstack_top - 1 >= 0 */
 
50458
 
 
50459
        entry_callstack_index = entry_callstack_top - 1;
 
50460
 
 
50461
        /* 'thr' is the current thread, as no-one resumes except us and we
 
50462
         * switch 'thr' in that case.
 
50463
         */
 
50464
 
 
50465
        /*
 
50466
         *  (Re)try handling the longjmp.
 
50467
         *
 
50468
         *  A longjmp handler may convert the longjmp to a different type and
 
50469
         *  "virtually" rethrow by goto'ing to 'check_longjmp'.  Before the goto,
 
50470
         *  the following must be updated:
 
50471
         *    - the heap 'lj' state
 
50472
         *    - 'thr' must reflect the "throwing" thread
 
50473
         */
 
50474
 
 
50475
 check_longjmp:
 
50476
 
 
50477
        DUK_DDPRINT("handling longjmp: type=%d, value1=%!T, value2=%!T, iserror=%d",
 
50478
                    thr->heap->lj.type,
 
50479
                    &thr->heap->lj.value1,
 
50480
                    &thr->heap->lj.value2,
 
50481
                    thr->heap->lj.iserror);
 
50482
 
 
50483
        switch (thr->heap->lj.type) {
 
50484
 
 
50485
        case DUK_LJ_TYPE_RESUME: {
 
50486
                /*
 
50487
                 *  Note: lj.value1 is 'value', lj.value2 is 'resumee'.
 
50488
                 *  This differs from YIELD.
 
50489
                 */
 
50490
 
 
50491
                duk_tval *tv;
 
50492
                duk_tval *tv2;
 
50493
                int act_idx;
 
50494
                duk_hthread *resumee;
 
50495
 
 
50496
                /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
 
50497
 
 
50498
                DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);                                                         /* unchanged by Duktape.Thread.resume() */
 
50499
                DUK_ASSERT(thr->callstack_top >= 2);                                                                         /* Ecmascript activation + Duktape.Thread.resume() activation */
 
50500
                DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL &&
 
50501
                           DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func) &&
 
50502
                           ((duk_hnativefunction *) (thr->callstack + thr->callstack_top - 1)->func)->func == duk_bi_thread_resume);
 
50503
                DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL &&
 
50504
                           DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func));                /* an Ecmascript function */
 
50505
                DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0);                                      /* waiting for a value */
 
50506
 
 
50507
                tv = &thr->heap->lj.value2;  /* resumee */
 
50508
                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
50509
                DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
 
50510
                DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
 
50511
                resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
 
50512
 
 
50513
                DUK_ASSERT(resumee != NULL);
 
50514
                DUK_ASSERT(resumee->resumer == NULL);
 
50515
                DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
 
50516
                           resumee->state == DUK_HTHREAD_STATE_YIELDED);                                                     /* checked by Duktape.Thread.resume() */
 
50517
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
 
50518
                           resumee->callstack_top >= 2);                                                                     /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
 
50519
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
 
50520
                           ((resumee->callstack + resumee->callstack_top - 1)->func != NULL &&
 
50521
                            DUK_HOBJECT_IS_NATIVEFUNCTION((resumee->callstack + resumee->callstack_top - 1)->func) &&
 
50522
                            ((duk_hnativefunction *) (resumee->callstack + resumee->callstack_top - 1)->func)->func == duk_bi_thread_yield));
 
50523
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
 
50524
                           ((resumee->callstack + resumee->callstack_top - 2)->func != NULL &&
 
50525
                            DUK_HOBJECT_IS_COMPILEDFUNCTION((resumee->callstack + resumee->callstack_top - 2)->func)));      /* an Ecmascript function */
 
50526
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
 
50527
                           (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0);                              /* waiting for a value */
 
50528
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||                                                   /* INACTIVE: no activation, single function value on valstack */
 
50529
                           resumee->callstack_top == 0);
 
50530
                DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
 
50531
                           (resumee->valstack_top == resumee->valstack + 1 &&
 
50532
                            DUK_TVAL_IS_OBJECT(resumee->valstack_top - 1) &&
 
50533
                            DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(resumee->valstack_top - 1))));
 
50534
 
 
50535
                if (thr->heap->lj.iserror) {
 
50536
                        /*
 
50537
                         *  Throw the error in the resumed thread's context; the
 
50538
                         *  error value is pushed onto the resumee valstack.
 
50539
                         *
 
50540
                         *  Note: the callstack of the target may empty in this case
 
50541
                         *  too (i.e. the target thread has never been resumed).  The
 
50542
                         *  value stack will contain the initial function in that case,
 
50543
                         *  which we simply ignore.
 
50544
                         */
 
50545
 
 
50546
                        resumee->resumer = thr;
 
50547
                        resumee->state = DUK_HTHREAD_STATE_RUNNING;
 
50548
                        thr->state = DUK_HTHREAD_STATE_RESUMED; 
 
50549
                        DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
 
50550
                        thr = resumee;
 
50551
 
 
50552
                        thr->heap->lj.type = DUK_LJ_TYPE_THROW;
 
50553
 
 
50554
                        /* thr->heap->lj.value1 is already the value to throw */
 
50555
                        /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
 
50556
 
 
50557
                        DUK_ASSERT(thr->heap->lj.iserror);  /* already set */
 
50558
 
 
50559
                        DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate");
 
50560
                        goto check_longjmp;
 
50561
                } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
 
50562
                        act_idx = resumee->callstack_top - 2;  /* Ecmascript function */
 
50563
                        DUK_ASSERT(resumee->callstack[act_idx].idx_retval >= 0);
 
50564
 
 
50565
                        tv = &resumee->valstack[resumee->callstack[act_idx].idx_retval];  /* return value from Duktape.Thread.yield() */
 
50566
                        DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
 
50567
                        tv2 = &thr->heap->lj.value1;
 
50568
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
50569
                        DUK_TVAL_SET_TVAL(tv, tv2);
 
50570
                        DUK_TVAL_INCREF(thr, tv);
 
50571
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50572
 
 
50573
                        duk_hthread_callstack_unwind(resumee, act_idx + 1);  /* unwind to 'yield' caller */
 
50574
 
 
50575
                        /* no need to unwind catchstack */
 
50576
 
 
50577
                        duk__reconfig_valstack(resumee, act_idx, 1);  /* 1 = have retval */
 
50578
 
 
50579
                        resumee->resumer = thr;
 
50580
                        resumee->state = DUK_HTHREAD_STATE_RUNNING;
 
50581
                        thr->state = DUK_HTHREAD_STATE_RESUMED;
 
50582
                        DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
 
50583
#if 0
 
50584
                        thr = resumee;  /* not needed, as we exit right away */
 
50585
#endif
 
50586
                        DUK_DDPRINT("-> resume with a value, restart execution in resumee");    
 
50587
                        retval = DUK__LONGJMP_RESTART;
 
50588
                        goto wipe_and_return;
 
50589
                } else {
 
50590
                        int call_flags;
 
50591
 
 
50592
                        /* resumee: [... initial_func]  (currently actually: [initial_func]) */
 
50593
 
 
50594
                        duk_push_undefined((duk_context *) resumee);
 
50595
                        tv = &thr->heap->lj.value1;
 
50596
                        duk_push_tval((duk_context *) resumee, tv);
 
50597
 
 
50598
                        /* resumee: [... initial_func undefined(= this) resume_value ] */
 
50599
 
 
50600
                        call_flags = DUK_CALL_FLAG_IS_RESUME;  /* is resume, not a tailcall */
 
50601
 
 
50602
                        duk_handle_ecma_call_setup(resumee,
 
50603
                                                   1,              /* num_stack_args */
 
50604
                                                   call_flags);    /* call_flags */
 
50605
 
 
50606
                        resumee->resumer = thr;
 
50607
                        resumee->state = DUK_HTHREAD_STATE_RUNNING;
 
50608
                        thr->state = DUK_HTHREAD_STATE_RESUMED;
 
50609
                        DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
 
50610
#if 0
 
50611
                        thr = resumee;  /* not needed, as we exit right away */
 
50612
#endif
 
50613
                        DUK_DDPRINT("-> resume with a value, restart execution in resumee");    
 
50614
                        retval = DUK__LONGJMP_RESTART;
 
50615
                        goto wipe_and_return;
 
50616
                }
 
50617
                DUK_UNREACHABLE();
 
50618
                break;  /* never here */
 
50619
        }
 
50620
 
 
50621
        case DUK_LJ_TYPE_YIELD: {
 
50622
                /*
 
50623
                 *  Currently only allowed only if yielding thread has only
 
50624
                 *  Ecmascript activations (except for the Duktape.Thread.yield()
 
50625
                 *  call at the callstack top) and none of them constructor
 
50626
                 *  calls.
 
50627
                 *
 
50628
                 *  This excludes the 'entry' thread which will always have
 
50629
                 *  a preventcount > 0.
 
50630
                 */
 
50631
 
 
50632
                duk_hthread *resumer;
 
50633
 
 
50634
                /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
 
50635
 
 
50636
                DUK_ASSERT(thr != entry_thread);                                                                             /* Duktape.Thread.yield() should prevent */
 
50637
                DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);                                                         /* unchanged from Duktape.Thread.yield() */
 
50638
                DUK_ASSERT(thr->callstack_top >= 2);                                                                         /* Ecmascript activation + Duktape.Thread.yield() activation */
 
50639
                DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL &&
 
50640
                           DUK_HOBJECT_IS_NATIVEFUNCTION((thr->callstack + thr->callstack_top - 1)->func) &&
 
50641
                           ((duk_hnativefunction *) (thr->callstack + thr->callstack_top - 1)->func)->func == duk_bi_thread_yield);
 
50642
                DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->func != NULL &&
 
50643
                           DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func));                /* an Ecmascript function */
 
50644
                DUK_ASSERT((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0);                                      /* waiting for a value */
 
50645
 
 
50646
                resumer = thr->resumer;
 
50647
 
 
50648
                DUK_ASSERT(resumer != NULL);
 
50649
                DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED);                                                     /* written by a previous RESUME handling */
 
50650
                DUK_ASSERT(resumer->callstack_top >= 2);                                                                     /* Ecmascript activation + Duktape.Thread.resume() activation */
 
50651
                DUK_ASSERT((resumer->callstack + resumer->callstack_top - 1)->func != NULL &&
 
50652
                           DUK_HOBJECT_IS_NATIVEFUNCTION((resumer->callstack + resumer->callstack_top - 1)->func) &&
 
50653
                           ((duk_hnativefunction *) (resumer->callstack + resumer->callstack_top - 1)->func)->func == duk_bi_thread_resume);
 
50654
                DUK_ASSERT((resumer->callstack + resumer->callstack_top - 2)->func != NULL &&
 
50655
                           DUK_HOBJECT_IS_COMPILEDFUNCTION((resumer->callstack + resumer->callstack_top - 2)->func));        /* an Ecmascript function */
 
50656
                DUK_ASSERT((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0);                              /* waiting for a value */
 
50657
 
 
50658
                if (thr->heap->lj.iserror) {
 
50659
                        thr->state = DUK_HTHREAD_STATE_YIELDED;
 
50660
                        thr->resumer = NULL;
 
50661
                        resumer->state = DUK_HTHREAD_STATE_RUNNING;
 
50662
                        DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
 
50663
                        thr = resumer;
 
50664
 
 
50665
                        thr->heap->lj.type = DUK_LJ_TYPE_THROW;
 
50666
                        /* lj.value1 is already set */
 
50667
                        DUK_ASSERT(thr->heap->lj.iserror);  /* already set */
 
50668
 
 
50669
                        DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate");
 
50670
                        goto check_longjmp;
 
50671
                } else {
 
50672
                        duk__handle_yield(thr, resumer, resumer->callstack_top - 2);
 
50673
 
 
50674
                        thr->state = DUK_HTHREAD_STATE_YIELDED;
 
50675
                        thr->resumer = NULL;
 
50676
                        resumer->state = DUK_HTHREAD_STATE_RUNNING;
 
50677
                        DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
 
50678
#if 0
 
50679
                        thr = resumer;  /* not needed, as we exit right away */
 
50680
#endif
 
50681
 
 
50682
                        DUK_DDPRINT("-> yield a value, restart execution in resumer");
 
50683
                        retval = DUK__LONGJMP_RESTART;
 
50684
                        goto wipe_and_return;
 
50685
                }
 
50686
                DUK_UNREACHABLE();
 
50687
                break;  /* never here */
 
50688
        }
 
50689
 
 
50690
        case DUK_LJ_TYPE_RETURN: {
 
50691
                /*
 
50692
                 *  Four possible outcomes:
 
50693
                 *    * A 'finally' in the same function catches the 'return'.
 
50694
                 *      (or)
 
50695
                 *    * The return happens at the entry level of the bytecode
 
50696
                 *      executor, so return from the executor (in C stack).
 
50697
                 *      (or)
 
50698
                 *    * There is a calling (Ecmascript) activation in the call
 
50699
                 *      stack => return to it.
 
50700
                 *      (or)
 
50701
                 *    * There is no calling activation, and the thread is
 
50702
                 *      terminated.  There is always a resumer in this case,
 
50703
                 *      which gets the return value similarly to a 'yield'
 
50704
                 *      (except that the current thread can no longer be
 
50705
                 *      resumed).
 
50706
                 */
 
50707
 
 
50708
                duk_tval *tv1;
 
50709
                duk_hthread *resumer;
 
50710
                duk_catcher *cat;
 
50711
                duk_size_t orig_callstack_index;
 
50712
 
 
50713
                DUK_ASSERT(thr != NULL);
 
50714
                DUK_ASSERT(thr->callstack_top >= 1);
 
50715
                DUK_ASSERT(thr->catchstack != NULL);
 
50716
 
 
50717
                /* FIXME: does not work if thr->catchstack is NULL */
 
50718
                /* FIXME: does not work if thr->catchstack is allocated but lowest pointer */
 
50719
 
 
50720
                cat = thr->catchstack + thr->catchstack_top - 1;  /* may be < thr->catchstack initially */
 
50721
                DUK_ASSERT(thr->callstack_top > 0);  /* ensures callstack_top - 1 >= 0 */
 
50722
                orig_callstack_index = thr->callstack_top - 1;
 
50723
 
 
50724
                while (cat >= thr->catchstack) {
 
50725
                        if (cat->callstack_index != orig_callstack_index) {
 
50726
                                break;
 
50727
                        }
 
50728
                        if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
 
50729
                            DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
 
50730
                                /* 'finally' catches */
 
50731
                                duk__handle_catch_or_finally(thr,
 
50732
                                                             cat - thr->catchstack,
 
50733
                                                             1); /* is_finally */
 
50734
 
 
50735
                                DUK_DDPRINT("-> return caught by a finally (in the same function), restart execution");
 
50736
                                retval = DUK__LONGJMP_RESTART;
 
50737
                                goto wipe_and_return;
 
50738
                        }
 
50739
                        cat--;
 
50740
                }
 
50741
                /* if out of catchstack, cat = &thr->catchstack[-1] */
 
50742
 
 
50743
                DUK_DDPRINT("no catcher in catch stack, return to calling activation / yield");
 
50744
 
 
50745
                /* return to calling activation (if any) */
 
50746
 
 
50747
                if (thr == entry_thread &&
 
50748
                    thr->callstack_top == entry_callstack_top) {
 
50749
                        /* return to the bytecode executor caller */
 
50750
 
 
50751
                        duk_push_tval((duk_context *) thr, &thr->heap->lj.value1);
 
50752
 
 
50753
                        /* [ ... retval ] */
 
50754
 
 
50755
                        DUK_DDPRINT("-> return propagated up to entry level, exit bytecode executor");
 
50756
                        retval = DUK__LONGJMP_FINISHED;
 
50757
                        goto wipe_and_return;
 
50758
                }
 
50759
 
 
50760
                if (thr->callstack_top >= 2) {
 
50761
                        /* there is a caller; it MUST be an Ecmascript caller (otherwise it would
 
50762
                         * match entry level check)
 
50763
                         */
 
50764
 
 
50765
                        DUK_DDDPRINT("slow return to Ecmascript caller, idx_retval=%d, lj_value1=%!T",
 
50766
                                     (thr->callstack + thr->callstack_top - 2)->idx_retval, &thr->heap->lj.value1);
 
50767
 
 
50768
                        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 2)->func));   /* must be ecmascript */
 
50769
 
 
50770
                        tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
 
50771
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
50772
                        DUK_TVAL_SET_TVAL(tv1, &thr->heap->lj.value1);
 
50773
                        DUK_TVAL_INCREF(thr, tv1);
 
50774
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
50775
 
 
50776
                        DUK_DDDPRINT("return value at idx_retval=%d is %!T",
 
50777
                                     (thr->callstack + thr->callstack_top - 2)->idx_retval,
 
50778
                                     thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval);
 
50779
 
 
50780
                        duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1);  /* leave 'cat' as top catcher (also works if catchstack exhausted) */
 
50781
                        duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
 
50782
                        duk__reconfig_valstack(thr, thr->callstack_top - 1, 1);    /* new top, i.e. callee */
 
50783
 
 
50784
                        DUK_DDPRINT("-> return not caught, restart execution in caller");
 
50785
                        retval = DUK__LONGJMP_RESTART;
 
50786
                        goto wipe_and_return;
 
50787
                }
 
50788
        
 
50789
                DUK_DDPRINT("no calling activation, thread finishes (similar to yield)");
 
50790
 
 
50791
                DUK_ASSERT(thr->resumer != NULL);
 
50792
                DUK_ASSERT(thr->resumer->callstack_top >= 2);  /* Ecmascript activation + Duktape.Thread.resume() activation */
 
50793
                DUK_ASSERT((thr->resumer->callstack + thr->resumer->callstack_top - 1)->func != NULL &&
 
50794
                           DUK_HOBJECT_IS_NATIVEFUNCTION((thr->resumer->callstack + thr->resumer->callstack_top - 1)->func) &&
 
50795
                           ((duk_hnativefunction *) (thr->resumer->callstack + thr->resumer->callstack_top - 1)->func)->func == duk_bi_thread_resume);  /* Duktape.Thread.resume() */
 
50796
                DUK_ASSERT((thr->resumer->callstack + thr->resumer->callstack_top - 2)->func != NULL &&
 
50797
                           DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->resumer->callstack + thr->resumer->callstack_top - 2)->func));  /* an Ecmascript function */
 
50798
                DUK_ASSERT((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0);                        /* waiting for a value */
 
50799
                DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
 
50800
                DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
 
50801
 
 
50802
                resumer = thr->resumer;
 
50803
 
 
50804
                duk__handle_yield(thr, resumer, resumer->callstack_top - 2);
 
50805
 
 
50806
                duk_hthread_terminate(thr);  /* updates thread state, minimizes its allocations */
 
50807
                DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
 
50808
 
 
50809
                thr->resumer = NULL;
 
50810
                resumer->state = DUK_HTHREAD_STATE_RUNNING;
 
50811
                DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
 
50812
#if 0
 
50813
                thr = resumer;  /* not needed */
 
50814
#endif
 
50815
 
 
50816
                DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer");
 
50817
                retval = DUK__LONGJMP_RESTART;
 
50818
                goto wipe_and_return;
 
50819
        }
 
50820
 
 
50821
        case DUK_LJ_TYPE_BREAK:
 
50822
        case DUK_LJ_TYPE_CONTINUE: {
 
50823
                /*
 
50824
                 *  Find a matching label catcher or 'finally' catcher in
 
50825
                 *  the same function.
 
50826
                 *  
 
50827
                 *  A label catcher must always exist and will match unless
 
50828
                 *  a 'finally' captures the break/continue first.  It is the
 
50829
                 *  compiler's responsibility to ensure that labels are used
 
50830
                 *  correctly.
 
50831
                 */
 
50832
 
 
50833
                duk_catcher *cat;
 
50834
                duk_size_t orig_callstack_index;
 
50835
                duk_uint_t lj_label;
 
50836
 
 
50837
                cat = thr->catchstack + thr->catchstack_top - 1;
 
50838
                orig_callstack_index = cat->callstack_index;
 
50839
 
 
50840
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(&thr->heap->lj.value1));
 
50841
                lj_label = (duk_uint_t) DUK_TVAL_GET_NUMBER(&thr->heap->lj.value1);
 
50842
 
 
50843
                DUK_DDDPRINT("handling break/continue with label=%d, callstack index=%d",
 
50844
                             (int) lj_label, (int) cat->callstack_index);
 
50845
 
 
50846
                while (cat >= thr->catchstack) {
 
50847
                        if (cat->callstack_index != orig_callstack_index) {
 
50848
                                break;
 
50849
                        }
 
50850
                        DUK_DDDPRINT("considering catcher %d: type=%d label=%d",
 
50851
                                     (int) (cat - thr->catchstack),
 
50852
                                     DUK_CAT_GET_TYPE(cat), DUK_CAT_GET_LABEL(cat));
 
50853
 
 
50854
                        if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
 
50855
                            DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
 
50856
                                /* finally catches */
 
50857
                                duk__handle_catch_or_finally(thr,
 
50858
                                                             cat - thr->catchstack,
 
50859
                                                             1); /* is_finally */
 
50860
 
 
50861
                                DUK_DDPRINT("-> break/continue caught by a finally (in the same function), restart execution");
 
50862
                                retval = DUK__LONGJMP_RESTART;
 
50863
                                goto wipe_and_return;
 
50864
                        }
 
50865
                        if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
 
50866
                            (duk_uint_t) DUK_CAT_GET_LABEL(cat) == lj_label) {
 
50867
                                /* found label */
 
50868
                                duk__handle_label(thr,
 
50869
                                                  cat - thr->catchstack);
 
50870
 
 
50871
                                /* FIXME: reset valstack to 'nregs' (or assert it) */
 
50872
 
 
50873
                                DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution");   
 
50874
                                retval = DUK__LONGJMP_RESTART;
 
50875
                                goto wipe_and_return;
 
50876
                        }
 
50877
                        cat--;
 
50878
                }
 
50879
 
 
50880
                /* should never happen, but be robust */
 
50881
                DUK_DPRINT("break/continue not caught by anything in the current function (should never happen)");
 
50882
                goto convert_to_internal_error;
 
50883
        }
 
50884
 
 
50885
        case DUK_LJ_TYPE_THROW: {
 
50886
                /*
 
50887
                 *  Three possible outcomes:
 
50888
                 *    * A try or finally catcher is found => resume there.
 
50889
                 *      (or)
 
50890
                 *    * The error propagates to the bytecode executor entry
 
50891
                 *      level (and we're in the entry thread) => rethrow
 
50892
                 *      with a new longjmp(), after restoring the previous
 
50893
                 *      catchpoint.
 
50894
                 *    * The error is not caught in the current thread, so
 
50895
                 *      the thread finishes with an error.  This works like
 
50896
                 *      a yielded error, except that the thread is finished
 
50897
                 *      and can no longer be resumed.  (There is always a
 
50898
                 *      resumer in this case.)
 
50899
                 *
 
50900
                 *  Note: until we hit the entry level, there can only be
 
50901
                 *  Ecmascript activations.
 
50902
                 */
 
50903
 
 
50904
                duk_catcher *cat;
 
50905
                duk_hthread *resumer;
 
50906
 
 
50907
                cat = thr->catchstack + thr->catchstack_top - 1;
 
50908
                while (cat >= thr->catchstack) {
 
50909
                        if (thr == entry_thread &&
 
50910
                            cat->callstack_index < entry_callstack_index) {
 
50911
                                /* entry level reached */
 
50912
                                break;
 
50913
                        }
 
50914
 
 
50915
                        if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
 
50916
                                /* try catches */
 
50917
                                DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
 
50918
 
 
50919
                                duk__handle_catch_or_finally(thr,
 
50920
                                                             cat - thr->catchstack,
 
50921
                                                             0); /* is_finally */
 
50922
 
 
50923
                                DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution");
 
50924
                                retval = DUK__LONGJMP_RESTART;
 
50925
                                goto wipe_and_return;
 
50926
                        }
 
50927
 
 
50928
                        if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
 
50929
                                DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
 
50930
                                DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
 
50931
 
 
50932
                                duk__handle_catch_or_finally(thr,
 
50933
                                                             cat - thr->catchstack,
 
50934
                                                             1); /* is_finally */
 
50935
 
 
50936
                                /* FIXME: reset valstack to 'nregs' (or assert it) */
 
50937
 
 
50938
                                DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution");
 
50939
                                retval = DUK__LONGJMP_RESTART;
 
50940
                                goto wipe_and_return;
 
50941
                        }
 
50942
 
 
50943
                        cat--;
 
50944
                }
 
50945
 
 
50946
                if (thr == entry_thread) {
 
50947
                        /* not caught by anything before entry level; rethrow and let the
 
50948
                         * final catcher unwind everything
 
50949
                         */
 
50950
#if 0
 
50951
                        duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1);  /* leave 'cat' as top catcher (also works if catchstack exhausted) */
 
50952
                        duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
 
50953
 
 
50954
#endif
 
50955
                        DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor");
 
50956
                        retval = DUK__LONGJMP_RETHROW;
 
50957
                        goto just_return;
 
50958
                        /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
 
50959
                }
 
50960
 
 
50961
                DUK_DDPRINT("not caught by current thread, yield error to resumer");
 
50962
 
 
50963
                /* not caught by current thread, thread terminates (yield error to resumer);
 
50964
                 * note that this may cause a cascade if the resumer terminates with an uncaught
 
50965
                 * exception etc (this is OK, but needs careful testing)
 
50966
                 */
 
50967
 
 
50968
                DUK_ASSERT(thr->resumer != NULL);
 
50969
                DUK_ASSERT(thr->resumer->callstack_top >= 2);  /* Ecmascript activation + Duktape.Thread.resume() activation */
 
50970
                DUK_ASSERT((thr->resumer->callstack + thr->resumer->callstack_top - 1)->func != NULL &&
 
50971
                           DUK_HOBJECT_IS_NATIVEFUNCTION((thr->resumer->callstack + thr->resumer->callstack_top - 1)->func) &&
 
50972
                           ((duk_hnativefunction *) (thr->resumer->callstack + thr->resumer->callstack_top - 1)->func)->func == duk_bi_thread_resume);  /* Duktape.Thread.resume() */
 
50973
                DUK_ASSERT((thr->resumer->callstack + thr->resumer->callstack_top - 2)->func != NULL &&
 
50974
                           DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->resumer->callstack + thr->resumer->callstack_top - 2)->func));  /* an Ecmascript function */
 
50975
 
 
50976
                resumer = thr->resumer;
 
50977
 
 
50978
                /* reset longjmp */
 
50979
 
 
50980
                DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);  /* already set */
 
50981
                /* lj.value1 already set */
 
50982
 
 
50983
                duk_hthread_terminate(thr);  /* updates thread state, minimizes its allocations */
 
50984
                DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
 
50985
 
 
50986
                thr->resumer = NULL;
 
50987
                resumer->state = DUK_HTHREAD_STATE_RUNNING;
 
50988
                DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
 
50989
                thr = resumer;
 
50990
                goto check_longjmp;
 
50991
        }
 
50992
 
 
50993
        case DUK_LJ_TYPE_NORMAL: {
 
50994
                DUK_DPRINT("caught DUK_LJ_TYPE_NORMAL, should never happen, treat as internal error");
 
50995
                goto convert_to_internal_error;
 
50996
        }
 
50997
 
 
50998
        default: {
 
50999
                /* should never happen, but be robust */
 
51000
                DUK_DPRINT("caught unknown longjmp type %d, treat as internal error", (int) thr->heap->lj.type);
 
51001
                goto convert_to_internal_error;
 
51002
        }
 
51003
 
 
51004
        }  /* end switch */
 
51005
 
 
51006
        DUK_UNREACHABLE();
 
51007
 
 
51008
 wipe_and_return:
 
51009
        /* this is not strictly necessary, but helps debugging */
 
51010
        thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
 
51011
        thr->heap->lj.iserror = 0;
 
51012
 
 
51013
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value1);
 
51014
        DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value1);
 
51015
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51016
 
 
51017
        DUK_TVAL_SET_TVAL(&tv_tmp, &thr->heap->lj.value2);
 
51018
        DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->heap->lj.value2);
 
51019
        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51020
 
 
51021
 just_return:
 
51022
        return retval;
 
51023
 
 
51024
 convert_to_internal_error:
 
51025
        /* This could also be thrown internally (set the error, goto check_longjmp),
 
51026
         * but it's better for internal errors to bubble outwards.
 
51027
         */
 
51028
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "internal error in bytecode executor longjmp handler");
 
51029
        DUK_UNREACHABLE();
 
51030
        return retval;
 
51031
}
 
51032
 
 
51033
/*
 
51034
 *  Executor interrupt handling
 
51035
 *
 
51036
 *  The handler is called whenever the interrupt countdown reaches zero
 
51037
 *  (or below).  The handler must perform whatever checks are activated,
 
51038
 *  e.g. check for cumulative step count to impose an execution step
 
51039
 *  limit or check for breakpoints or other debugger interaction.
 
51040
 *
 
51041
 *  When the actions are done, the handler must reinit the interrupt
 
51042
 *  init and counter values.  The 'init' value must indicate how many
 
51043
 *  bytecode instructions are executed before the next interrupt.  The
 
51044
 *  counter must interface with the bytecode executor loop.  Concretely,
 
51045
 *  the new init value is normally one higher than the new counter value.
 
51046
 *  For instance, to execute exactly one bytecode instruction the init
 
51047
 *  value is set to 1 and the counter to 0.  If an error is thrown by the
 
51048
 *  interrupt handler, the counters are set to the same value (e.g. both
 
51049
 *  to 0 to cause an interrupt when the next bytecode instruction is about
 
51050
 *  to be executed after error handling).
 
51051
 *
 
51052
 *  Maintaining the init/counter value properly is important for accurate
 
51053
 *  behavior.  For instance, executor step limit needs a cumulative step
 
51054
 *  count which is simply computed as a sum of 'init' values.  This must
 
51055
 *  work accurately even when single stepping.
 
51056
 */
 
51057
 
 
51058
#ifdef DUK_USE_INTERRUPT_COUNTER
 
51059
static void duk__executor_interrupt(duk_hthread *thr) {
 
51060
        duk_int_t ctr;
 
51061
        duk_activation *act;
 
51062
        duk_hcompiledfunction *fun;
 
51063
 
 
51064
        DUK_ASSERT(thr != NULL);
 
51065
        DUK_ASSERT(thr->callstack != NULL);
 
51066
        DUK_ASSERT(thr->callstack_top > 0);
 
51067
 
 
51068
        act = thr->callstack + thr->callstack_top - 1;
 
51069
        fun = (duk_hcompiledfunction *) act->func;
 
51070
        DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION((duk_hobject *) fun));
 
51071
        DUK_UNREF(fun);
 
51072
 
 
51073
        ctr = DUK_HEAP_INTCTR_DEFAULT;
 
51074
 
 
51075
#if 0
 
51076
        /* FIXME: cumulative instruction count example */
 
51077
        static int step_count = 0;
 
51078
        step_count += thr->heap->interrupt_init;
 
51079
        if (step_count >= 1000000) {
 
51080
                /* Keep throwing an error whenever we get here.  The unusual values
 
51081
                 * are set this way because no instruction is ever executed, we just
 
51082
                 * throw an error until all try/catch/finally and other catchpoints
 
51083
                 * have been exhausted.
 
51084
                 */
 
51085
                DUK_DPRINT("execution step limit reached, throwing a RangeError");
 
51086
                thr->heap->interrupt_init = 0;
 
51087
                thr->heap->interrupt_counter = 0;
 
51088
                thr->interrupt_counter = 0;
 
51089
                DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "execution step limit");
 
51090
        }
 
51091
#endif
 
51092
 
 
51093
#if 0
 
51094
        /* FIXME: debugger integration: single step, breakpoint checks, etc */
 
51095
        if (0) {
 
51096
                /* Cause an interrupt after executing one instruction. */
 
51097
                ctr = 1;
 
51098
        }
 
51099
#endif
 
51100
 
 
51101
        DUK_DDDPRINT("executor interrupt finished, cstop=%d, pc=%d, nextctr=%d",
 
51102
                     (int) thr->callstack_top, (int) act->pc, (int) ctr);
 
51103
 
 
51104
        /* The counter value is one less than the init value: init value should
 
51105
         * indicate how many instructions are executed before interrupt.  To
 
51106
         * execute 1 instruction, counter must be 0.
 
51107
         */
 
51108
        thr->heap->interrupt_init = ctr;
 
51109
        thr->heap->interrupt_counter = ctr - 1;
 
51110
        thr->interrupt_counter = ctr - 1;
 
51111
}
 
51112
#endif  /* DUK_USE_INTERRUPT_COUNTER */
 
51113
 
 
51114
/*
 
51115
 *  Ecmascript bytecode executor.
 
51116
 *
 
51117
 *  Resume execution for the current thread from its current activation.
 
51118
 *  Returns when execution would return from the entry level activation,
 
51119
 *  leaving a single return value on top of the stack.  Function calls
 
51120
 *  and thread resumptions are handled internally.  If an error occurs,
 
51121
 *  a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
 
51122
 *  setjmp() jmpbuf.
 
51123
 *
 
51124
 *  Ecmascript function calls and coroutine resumptions are handled
 
51125
 *  internally without recursive C calls.  Other function calls are
 
51126
 *  handled using duk_handle_call(), increasing C recursion depth.
 
51127
 *
 
51128
 *  There are many other tricky control flow situations, such as:
 
51129
 *
 
51130
 *    - Break and continue (fast and slow)
 
51131
 *    - Return (fast and slow)
 
51132
 *    - Error throwing
 
51133
 *    - Thread resume and yield
 
51134
 *
 
51135
 *  For more detailed notes, see doc/execution.txt.
 
51136
 *
 
51137
 *  Note: setjmp() and local variables have a nasty interaction,
 
51138
 *  see execution.txt; non-volatile locals modified after setjmp()
 
51139
 *  call are not guaranteed to keep their value.
 
51140
 */
 
51141
 
 
51142
#define DUK__STRICT()       (DUK_HOBJECT_HAS_STRICT(&(fun)->obj))
 
51143
#define DUK__REG(x)         (thr->valstack_bottom[(x)])
 
51144
#define DUK__REGP(x)        (&thr->valstack_bottom[(x)])
 
51145
#define DUK__CONST(x)       (DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(fun)[(x)])
 
51146
#define DUK__CONSTP(x)      (&DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(fun)[(x)])
 
51147
#define DUK__REGCONST(x)    ((x) < DUK_BC_REGLIMIT ? DUK__REG((x)) : DUK__CONST((x) - DUK_BC_REGLIMIT))
 
51148
#define DUK__REGCONSTP(x)   ((x) < DUK_BC_REGLIMIT ? DUK__REGP((x)) : DUK__CONSTP((x) - DUK_BC_REGLIMIT))
 
51149
 
 
51150
#ifdef DUK_USE_VERBOSE_EXECUTOR_ERRORS
 
51151
#define DUK__INTERNAL_ERROR(msg)  do { \
 
51152
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, (msg)); \
 
51153
        } while (0)
 
51154
#else
 
51155
#define DUK__INTERNAL_ERROR(msg)  do { \
 
51156
                goto internal_error; \
 
51157
        } while (0)
 
51158
#endif
 
51159
 
 
51160
void duk_js_execute_bytecode(duk_hthread *entry_thread) {
 
51161
        /* entry level info */
 
51162
        duk_size_t entry_callstack_top;
 
51163
        int entry_call_recursion_depth;
 
51164
        duk_jmpbuf *entry_jmpbuf_ptr;
 
51165
 
 
51166
        /* "hot" variables for interpretation -- not volatile, value not guaranteed in setjmp error handling */
 
51167
        duk_hthread *thr;             /* stable */
 
51168
        duk_activation *act;          /* semi-stable (ok as long as callstack not resized) */
 
51169
        duk_hcompiledfunction *fun;   /* stable */
 
51170
        duk_instr *bcode;             /* stable */
 
51171
        /* 'consts' is computed on-the-fly */
 
51172
        /* 'funcs' is quite rarely used, so no local for it */
 
51173
 
 
51174
        /* "hot" temps for interpretation -- not volatile, value not guaranteed in setjmp error handling */
 
51175
        duk_uint32_t ins;
 
51176
 
 
51177
        /* jmpbuf */
 
51178
        duk_jmpbuf jmpbuf;
 
51179
 
 
51180
#ifdef DUK_USE_INTERRUPT_COUNTER
 
51181
        duk_int_t int_ctr;
 
51182
#endif
 
51183
 
 
51184
#ifdef DUK_USE_ASSERTIONS
 
51185
        int valstack_top_base;    /* valstack top, should match before interpreting each op (no leftovers) */
 
51186
#endif
 
51187
 
 
51188
        /* FIXME: document assumptions on setjmp and volatile variables
 
51189
         * (see duk_handle_call()).
 
51190
         */
 
51191
 
 
51192
        /*
 
51193
         *  Preliminaries
 
51194
         */
 
51195
 
 
51196
        DUK_ASSERT(entry_thread != NULL);
 
51197
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) entry_thread);
 
51198
        DUK_ASSERT(entry_thread->callstack_top >= 1);  /* at least one activation, ours */
 
51199
        DUK_ASSERT((entry_thread->callstack + entry_thread->callstack_top - 1)->func != NULL);
 
51200
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((entry_thread->callstack + entry_thread->callstack_top - 1)->func));
 
51201
 
 
51202
        thr = entry_thread;
 
51203
 
 
51204
        entry_callstack_top = thr->callstack_top;
 
51205
        entry_call_recursion_depth = thr->heap->call_recursion_depth;
 
51206
        entry_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
 
51207
 
 
51208
        /*
 
51209
         *  Setjmp catchpoint setup.
 
51210
         *
 
51211
         *  Note: we currently assume that the setjmp() catchpoint is
 
51212
         *  not re-entrant (longjmp() cannot be called more than once
 
51213
         *  for a single setjmp()).
 
51214
         */
 
51215
 
 
51216
 reset_setjmp_catchpoint:
 
51217
 
 
51218
        DUK_ASSERT(thr != NULL);
 
51219
        thr->heap->lj.jmpbuf_ptr = &jmpbuf;
 
51220
        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);
 
51221
 
 
51222
        if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb)) {
 
51223
                /*
 
51224
                 *  Note: any local variables accessed here must have their value
 
51225
                 *  assigned *before* the setjmp() call, OR they must be declared
 
51226
                 *  volatile.  Otherwise their value is not guaranteed to be correct.
 
51227
                 *
 
51228
                 *  'thr' might seem to be a risky variable because it is changed
 
51229
                 *  for yield and resume.  However, yield and resume are handled
 
51230
                 *  using longjmp()s.
 
51231
                 */
 
51232
 
 
51233
                int lj_ret;
 
51234
 
 
51235
                /* FIXME: signalling the need to shrink check (only if unwound) */
 
51236
 
 
51237
                DUK_DDDPRINT("longjmp caught by bytecode executor, thr=%p, curr_thread=%p",
 
51238
                             thr, (thr && thr->heap) ? thr->heap->curr_thread : NULL);
 
51239
 
 
51240
                /* must be restored here to handle e.g. yields properly */
 
51241
                thr->heap->call_recursion_depth = entry_call_recursion_depth;
 
51242
 
 
51243
                /* Longjmp callers should not switch threads, the longjmp handler
 
51244
                 * does that (even for RESUME and YIELD).
 
51245
                 */
 
51246
 
 
51247
                DUK_ASSERT(thr != NULL);
 
51248
                DUK_ASSERT(thr == thr->heap->curr_thread);
 
51249
 
 
51250
                /* Switch to caller's setjmp() catcher so that if an error occurs
 
51251
                 * during error handling, it is always propagated outwards instead
 
51252
                 * of causing an infinite loop in our own handler.
 
51253
                 */
 
51254
 
 
51255
                DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p",
 
51256
                             (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
 
51257
                             entry_jmpbuf_ptr);
 
51258
                thr->heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
 
51259
 
 
51260
                lj_ret = duk__handle_longjmp(thr, entry_thread, entry_callstack_top);
 
51261
 
 
51262
                if (lj_ret == DUK__LONGJMP_RESTART) {
 
51263
                        /*
 
51264
                         *  Restart bytecode execution, possibly with a changed thread.
 
51265
                         */
 
51266
                        thr = thr->heap->curr_thread;
 
51267
                        goto reset_setjmp_catchpoint;
 
51268
                } else if (lj_ret == DUK__LONGJMP_RETHROW) {
 
51269
                        /*
 
51270
                         *  Rethrow error to calling state.
 
51271
                         */
 
51272
 
 
51273
                        /* thread may have changed (e.g. YIELD converted to THROW) */
 
51274
                        thr = thr->heap->curr_thread;
 
51275
 
 
51276
                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
 
51277
 
 
51278
                        duk_err_longjmp(thr);
 
51279
                        DUK_UNREACHABLE();
 
51280
                } else {
 
51281
                        /*
 
51282
                         *  Return from bytecode executor with a return value.
 
51283
                         */
 
51284
                        DUK_ASSERT(lj_ret == DUK__LONGJMP_FINISHED);
 
51285
 
 
51286
                        /* FIXME: return assertions for valstack, callstack, catchstack */
 
51287
 
 
51288
                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
 
51289
                        return;
 
51290
                }
 
51291
                DUK_UNREACHABLE();
 
51292
        }
 
51293
 
 
51294
        /*
 
51295
         *  Restart execution by reloading thread state.
 
51296
         *
 
51297
         *  Note that 'thr' and any thread configuration may have changed,
 
51298
         *  so all local variables are suspect.
 
51299
         *
 
51300
         *  The number of local variables should be kept to a minimum: if
 
51301
         *  the variables are spilled, they will need to be loaded from
 
51302
         *  memory anyway.
 
51303
         */
 
51304
 
 
51305
 restart_execution:
 
51306
 
 
51307
        /* Lookup current thread; note that we can use 'thr' for this even
 
51308
         * though it is not the current thread (any thread will do).
 
51309
         */
 
51310
        thr = thr->heap->curr_thread;
 
51311
#ifdef DUK_USE_INTERRUPT_COUNTER
 
51312
        thr->interrupt_counter = thr->heap->interrupt_counter;
 
51313
#endif
 
51314
 
 
51315
        DUK_ASSERT(thr != NULL);
 
51316
        DUK_ASSERT(thr->callstack_top >= 1);
 
51317
        DUK_ASSERT((thr->callstack + thr->callstack_top - 1)->func != NULL);
 
51318
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((thr->callstack + thr->callstack_top - 1)->func));
 
51319
 
 
51320
        /* FIXME: shrink check flag? */
 
51321
 
 
51322
        /* assume that thr->valstack_bottom has been set-up before getting here */
 
51323
        act = thr->callstack + thr->callstack_top - 1;
 
51324
        fun = (duk_hcompiledfunction *) act->func;
 
51325
        bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(fun);
 
51326
 
 
51327
        DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= fun->nregs);
 
51328
        DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);  /* XXX: correct? */
 
51329
 
 
51330
        /*
 
51331
         *  Bytecode interpreter.
 
51332
         *
 
51333
         *  The interpreter must be very careful with memory pointers, as
 
51334
         *  many pointers are not guaranteed to be 'stable' and may be
 
51335
         *  reallocated and relocated on-the-fly quite easily (e.g. by a
 
51336
         *  memory allocation or a property access).
 
51337
         *
 
51338
         *  The following are assumed to have stable pointers:
 
51339
         *    - the current thread
 
51340
         *    - the current function
 
51341
         *    - the bytecode, constant table, inner function table of the
 
51342
         *      current function (as they are a part of the function allocation)
 
51343
         *
 
51344
         *  The following are assumed to have semi-stable pointers:
 
51345
         *    - the current activation entry: stable as long as callstack
 
51346
         *      is not changed (reallocated by growing or shrinking), or
 
51347
         *      by any garbage collection invocation (through finalizers)
 
51348
         *    - Note in particular that ANY DECREF can invalidate the
 
51349
         *      activation pointer
 
51350
         *
 
51351
         *  The following are not assumed to have stable pointers at all:
 
51352
         *    - the value stack (registers) of the current thread
 
51353
         *    - the catch stack of the current thread
 
51354
         *
 
51355
         *  See execution.txt for discussion.
 
51356
         */
 
51357
 
 
51358
        DUK_ASSERT(thr != NULL);
 
51359
        DUK_ASSERT(act != NULL);
 
51360
        DUK_ASSERT(fun != NULL);
 
51361
        DUK_ASSERT(bcode != NULL);
 
51362
 
 
51363
        DUK_DDPRINT("restarting execution, thr %p, act %p (idx %d), fun %p, bcode %p, "
 
51364
                    "consts %p, funcs %p, lev %d, regbot %d, regtop %d, catchstack_top=%d, "
 
51365
                    "preventcount=%d",
 
51366
                    (void *) thr,
 
51367
                    (void *) act,
 
51368
                    thr->callstack_top - 1,
 
51369
                    (void *) fun,
 
51370
                    (void *) bcode,
 
51371
                    (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(fun),
 
51372
                    (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(fun),
 
51373
                    (int) (thr->callstack_top - 1),
 
51374
                    (int) (thr->valstack_bottom - thr->valstack),
 
51375
                    (int) (thr->valstack_top - thr->valstack),
 
51376
                    (int) thr->catchstack_top,
 
51377
                    (int) thr->callstack_preventcount);
 
51378
 
 
51379
#ifdef DUK_USE_ASSERTIONS
 
51380
        valstack_top_base = (int) (thr->valstack_top - thr->valstack);
 
51381
#endif
 
51382
 
 
51383
        for (;;) {
 
51384
                DUK_ASSERT(thr->callstack_top >= 1);
 
51385
                DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= fun->nregs);  /* FIXME == nregs? */
 
51386
                DUK_ASSERT((int) (thr->valstack_top - thr->valstack) == valstack_top_base);
 
51387
 
 
51388
                /* Executor interrupt counter check, used to implement breakpoints,
 
51389
                 * debugging interface, execution timeouts, etc.  The counter is heap
 
51390
                 * specific but is maintained in the current thread to make the check
 
51391
                 * as fast as possible.  The counter is copied back to the heap struct
 
51392
                 * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
 
51393
                 */
 
51394
#ifdef DUK_USE_INTERRUPT_COUNTER
 
51395
                int_ctr = thr->interrupt_counter;
 
51396
                if (DUK_LIKELY(int_ctr > 0)) {
 
51397
                        thr->interrupt_counter = int_ctr - 1;
 
51398
                } else {
 
51399
                        /* Trigger at zero or below */
 
51400
                        duk__executor_interrupt(thr);
 
51401
                }
 
51402
#endif
 
51403
 
 
51404
                /* Because ANY DECREF potentially invalidates 'act' now (through
 
51405
                 * finalization), we need to re-lookup 'act' in almost every case.
 
51406
                 *
 
51407
                 * FIXME:
 
51408
                 * This is not nice; it would be nice if the program counter was a
 
51409
                 * behind a stable pointer.  For instance, put a raw bytecode pointer
 
51410
                 * into duk_hthread struct (not into the callstack); since bytecode
 
51411
                 * has a stable pointer this would work nicely.  Whenever a call is
 
51412
                 * made, the bytecode pointer could be backed up as an integer index
 
51413
                 * to the calling activation.
 
51414
                 */
 
51415
 
 
51416
                act = thr->callstack + thr->callstack_top - 1;
 
51417
                DUK_ASSERT(bcode + act->pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(fun));
 
51418
                DUK_ASSERT(bcode + act->pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(fun));
 
51419
 
 
51420
                DUK_DDDPRINT("executing bytecode: pc=%d ins=0x%08x, op=%d, valstack_top=%d/%d  -->  %!I",
 
51421
                             act->pc, bcode[act->pc], DUK_DEC_OP(bcode[act->pc]),
 
51422
                             (int) (thr->valstack_top - thr->valstack),
 
51423
                             (int) (thr->valstack_end - thr->valstack),
 
51424
                             bcode[act->pc]);
 
51425
 
 
51426
                ins = bcode[act->pc++];
 
51427
 
 
51428
                switch (DUK_DEC_OP(ins)) {
 
51429
 
 
51430
                case DUK_OP_LDREG: {
 
51431
                        int t;
 
51432
                        duk_tval tv_tmp;
 
51433
                        duk_tval *tv1, *tv2;
 
51434
 
 
51435
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51436
                        t = DUK_DEC_BC(ins); tv2 = DUK__REGP(t);
 
51437
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
51438
                        DUK_TVAL_SET_TVAL(tv1, tv2);
 
51439
                        DUK_TVAL_INCREF(thr, tv1);
 
51440
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51441
                        break;
 
51442
                }
 
51443
 
 
51444
                case DUK_OP_STREG: {
 
51445
                        int t;
 
51446
                        duk_tval tv_tmp;
 
51447
                        duk_tval *tv1, *tv2;
 
51448
 
 
51449
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51450
                        t = DUK_DEC_BC(ins); tv2 = DUK__REGP(t);
 
51451
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
 
51452
                        DUK_TVAL_SET_TVAL(tv2, tv1);
 
51453
                        DUK_TVAL_INCREF(thr, tv2);
 
51454
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51455
                        break;
 
51456
                }
 
51457
 
 
51458
                case DUK_OP_LDCONST: {
 
51459
                        int t;
 
51460
                        duk_tval tv_tmp;
 
51461
                        duk_tval *tv1, *tv2;
 
51462
 
 
51463
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51464
                        t = DUK_DEC_BC(ins); tv2 = DUK__CONSTP(t);
 
51465
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
51466
                        DUK_TVAL_SET_TVAL(tv1, tv2);
 
51467
                        DUK_TVAL_INCREF(thr, tv2);  /* may be e.g. string */
 
51468
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51469
                        break;
 
51470
                }
 
51471
 
 
51472
                case DUK_OP_LDINT: {
 
51473
                        int t;
 
51474
                        duk_tval tv_tmp;
 
51475
                        duk_tval *tv1;
 
51476
                        double val;
 
51477
 
 
51478
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51479
                        t = DUK_DEC_BC(ins); val = (double) (t - DUK_BC_LDINT_BIAS);
 
51480
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
51481
                        DUK_TVAL_SET_NUMBER(tv1, val);
 
51482
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
51483
                        break;
 
51484
                }
 
51485
 
 
51486
                case DUK_OP_LDINTX: {
 
51487
                        int t;
 
51488
                        duk_tval *tv1;
 
51489
                        double val;
 
51490
 
 
51491
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51492
                        if (!DUK_TVAL_IS_NUMBER(tv1)) {
 
51493
                                DUK__INTERNAL_ERROR("LDINTX target not a number");
 
51494
                        }
 
51495
                        val = DUK_TVAL_GET_NUMBER(tv1) * ((double) (1 << DUK_BC_LDINTX_SHIFT)) +
 
51496
                              (double) DUK_DEC_BC(ins);
 
51497
                        DUK_TVAL_SET_NUMBER(tv1, val);
 
51498
                        break;
 
51499
                }
 
51500
 
 
51501
                case DUK_OP_MPUTOBJ:
 
51502
                case DUK_OP_MPUTOBJI: {
 
51503
                        duk_context *ctx = (duk_context *) thr;
 
51504
                        int t;
 
51505
                        duk_tval *tv1;
 
51506
                        duk_hobject *obj;
 
51507
                        int idx;
 
51508
                        int count;
 
51509
 
 
51510
                        /* A -> register of target object
 
51511
                         * B -> first register of key/value pair list
 
51512
                         * C -> number of key/value pairs
 
51513
                         */
 
51514
 
 
51515
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51516
                        if (!DUK_TVAL_IS_OBJECT(tv1)) {
 
51517
                                DUK__INTERNAL_ERROR("MPUTOBJ target not an object");
 
51518
                        }
 
51519
                        obj = DUK_TVAL_GET_OBJECT(tv1);
 
51520
 
 
51521
                        idx = (int) DUK_DEC_B(ins);
 
51522
                        if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
 
51523
                                duk_tval *tv_ind = DUK__REGP(idx);
 
51524
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
51525
                                        DUK__INTERNAL_ERROR("MPUTOBJI target is not a number");
 
51526
                                }
 
51527
                                idx = (int) DUK_TVAL_GET_NUMBER(tv_ind);
 
51528
                        }
 
51529
 
 
51530
                        count = (int) DUK_DEC_C(ins);
 
51531
 
 
51532
                        if (idx < 0 || idx + count * 2 > duk_get_top(ctx)) {
 
51533
                                /* XXX: improve check; check against nregs, not against top */
 
51534
                                DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
 
51535
                        }
 
51536
 
 
51537
                        duk_push_hobject(ctx, obj);
 
51538
 
 
51539
                        while (count > 0) {
 
51540
                                /* XXX: faster initialization (direct access or better primitives) */
 
51541
 
 
51542
                                duk_push_tval(ctx, DUK__REGP(idx));
 
51543
                                if (!duk_is_string(ctx, -1)) {
 
51544
                                        DUK__INTERNAL_ERROR("MPUTOBJ key not a string");
 
51545
                                }
 
51546
                                duk_push_tval(ctx, DUK__REGP(idx + 1));  /* -> [... obj key value] */
 
51547
                                duk_def_prop(ctx, -3, DUK_PROPDESC_FLAGS_WEC);  /* -> [... obj] */
 
51548
 
 
51549
                                count--;
 
51550
                                idx += 2;
 
51551
                        }
 
51552
 
 
51553
                        duk_pop(ctx);  /* [... obj] -> [...] */
 
51554
                        break;
 
51555
                }
 
51556
 
 
51557
                case DUK_OP_MPUTARR:
 
51558
                case DUK_OP_MPUTARRI: {
 
51559
                        duk_context *ctx = (duk_context *) thr;
 
51560
                        int t;
 
51561
                        duk_tval *tv1;
 
51562
                        duk_hobject *obj;
 
51563
                        int idx;
 
51564
                        int count;
 
51565
                        duk_uint32_t arr_idx;
 
51566
 
 
51567
                        /* A -> register of target object
 
51568
                         * B -> first register of value data (start_index, value1, value2, ..., valueN)
 
51569
                         * C -> number of key/value pairs (N)
 
51570
                         */
 
51571
 
 
51572
                        t = DUK_DEC_A(ins); tv1 = DUK__REGP(t);
 
51573
                        if (!DUK_TVAL_IS_OBJECT(tv1)) {
 
51574
                                DUK__INTERNAL_ERROR("MPUTARR target not an object");
 
51575
                        }
 
51576
                        obj = DUK_TVAL_GET_OBJECT(tv1);
 
51577
 
 
51578
                        idx = (int) DUK_DEC_B(ins);
 
51579
                        if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
 
51580
                                duk_tval *tv_ind = DUK__REGP(idx);
 
51581
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
51582
                                        DUK__INTERNAL_ERROR("MPUTARRI target is not a number");
 
51583
                                }
 
51584
                                idx = (int) DUK_TVAL_GET_NUMBER(tv_ind);
 
51585
                        }
 
51586
 
 
51587
                        count = (int) DUK_DEC_C(ins);
 
51588
 
 
51589
                        if (idx < 0 || idx + count + 1 > duk_get_top(ctx)) {
 
51590
                                /* XXX: improve check; check against nregs, not against top */
 
51591
                                DUK__INTERNAL_ERROR("MPUTARR out of bounds");
 
51592
                        }
 
51593
 
 
51594
                        tv1 = DUK__REGP(idx);
 
51595
                        if (!DUK_TVAL_IS_NUMBER(tv1)) {
 
51596
                                DUK__INTERNAL_ERROR("MPUTARR start index not a number");
 
51597
                        }
 
51598
                        arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
 
51599
                        idx++;
 
51600
 
 
51601
                        duk_push_hobject(ctx, obj);
 
51602
 
 
51603
                        while (count > 0) {
 
51604
                                /* duk_def_prop() will define an own property without any array
 
51605
                                 * special behaviors.  We'll need to set the array length explicitly
 
51606
                                 * in the end.  For arrays with elisions, the compiler will emit an
 
51607
                                 * explicit SETALEN which will update the length.
 
51608
                                 */
 
51609
 
 
51610
                                /*
 
51611
                                 * FIXME: because we're dealing with 'own' properties of a fresh array,
 
51612
                                 * the array initializer should just ensure that the array has a large
 
51613
                                 * enough array part and write the values directly into array part,
 
51614
                                 * and finally set 'length' manually in the end (as already happens now).
 
51615
                                 */
 
51616
 
 
51617
                                duk_push_tval(ctx, DUK__REGP(idx));                              /* -> [... obj value] */
 
51618
                                duk_def_prop_index(ctx, -2, arr_idx, DUK_PROPDESC_FLAGS_WEC);    /* -> [... obj] */
 
51619
 
 
51620
                                count--;
 
51621
                                idx++;
 
51622
                                arr_idx++;
 
51623
                        }
 
51624
 
 
51625
                        /* XXX: E5.1 Section 11.1.4 coerces the final length through
 
51626
                         * ToUint32() which is odd but happens now as a side effect of
 
51627
                         * 'arr_idx' type.
 
51628
                         */
 
51629
                        duk_hobject_set_length(thr, obj, arr_idx);
 
51630
 
 
51631
                        duk_pop(ctx);  /* [... obj] -> [...] */
 
51632
                        break;
 
51633
                }
 
51634
 
 
51635
                case DUK_OP_NEW:
 
51636
                case DUK_OP_NEWI: {
 
51637
                        duk_context *ctx = (duk_context *) thr;
 
51638
                        int b = DUK_DEC_B(ins);
 
51639
                        int c = DUK_DEC_C(ins);
 
51640
                        int i;
 
51641
 
 
51642
                        /* A -> unused (reserved for flags, for consistency with DUK_OP_CALL)
 
51643
                         * B -> target register and start reg: constructor, arg1, ..., argN
 
51644
                         *      (for DUK_OP_NEWI, 'b' is indirect)
 
51645
                         * C -> num args (N)
 
51646
                         */
 
51647
 
 
51648
                        /* Note: duk_new() will call the constuctor using duk_handle_call().
 
51649
                         * A constructor call prevents a yield from inside the constructor,
 
51650
                         * even if the constructor is an Ecmascript function.
 
51651
                         */
 
51652
 
 
51653
                        /* FIXME: unnecessary copying of values?  Just set 'top' to
 
51654
                         * b + c, and let the return handling fix up the stack frame?
 
51655
                         */
 
51656
 
 
51657
                        if (DUK_DEC_OP(ins) == DUK_OP_NEWI) {
 
51658
                                duk_tval *tv_ind = DUK__REGP(b);
 
51659
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
51660
                                        DUK__INTERNAL_ERROR("NEWI target is not a number");
 
51661
                                }
 
51662
                                b = (int) DUK_TVAL_GET_NUMBER(tv_ind);  /* not validated */
 
51663
                        }
 
51664
 
 
51665
                        duk_require_stack(ctx, c);
 
51666
                        duk_push_tval(ctx, DUK__REGP(b));
 
51667
                        for (i = 0; i < c; i++) {
 
51668
                                duk_push_tval(ctx, DUK__REGP(b + i + 1));
 
51669
                        }
 
51670
                        duk_new(ctx, c);  /* [... constructor arg1 ... argN] -> [retval] */
 
51671
                        DUK_DDDPRINT("NEW -> %!iT", duk_get_tval(ctx, -1));
 
51672
                        duk_replace(ctx, b);
 
51673
                        break;
 
51674
                }
 
51675
 
 
51676
                case DUK_OP_REGEXP: {
 
51677
#ifdef DUK_USE_REGEXP_SUPPORT
 
51678
                        duk_context *ctx = (duk_context *) thr;
 
51679
                        int a = DUK_DEC_A(ins);
 
51680
                        int b = DUK_DEC_B(ins);
 
51681
                        int c = DUK_DEC_C(ins);
 
51682
 
 
51683
                        /* A -> target register
 
51684
                         * B -> bytecode (also contains flags)
 
51685
                         * C -> escaped source
 
51686
                         */
 
51687
 
 
51688
                        duk_push_tval(ctx, DUK__REGCONSTP(c));
 
51689
                        duk_push_tval(ctx, DUK__REGCONSTP(b));  /* -> [ ... escaped_source bytecode ] */
 
51690
                        duk_regexp_create_instance(thr);   /* -> [ ... regexp_instance ] */
 
51691
                        DUK_DDDPRINT("regexp instance: %!iT", duk_get_tval(ctx, -1));
 
51692
                        duk_replace(ctx, a);
 
51693
#else
 
51694
                        /* The compiler should never emit DUK_OP_REGEXP if there is no
 
51695
                         * regexp support.
 
51696
                         */
 
51697
                        DUK__INTERNAL_ERROR("no regexp support");
 
51698
#endif
 
51699
 
 
51700
                        break;
 
51701
                }
 
51702
 
 
51703
                case DUK_OP_CSREG:
 
51704
                case DUK_OP_CSREGI: {
 
51705
                        /*
 
51706
                         *  Assuming a register binds to a variable declared within this
 
51707
                         *  function (a declarative binding), the 'this' for the call
 
51708
                         *  setup is always 'undefined'.  E5 Section 10.2.1.1.6.
 
51709
                         */
 
51710
 
 
51711
                        duk_context *ctx = (duk_context *) thr;
 
51712
                        int a = DUK_DEC_A(ins);
 
51713
                        int b = DUK_DEC_B(ins);  /* restricted to regs */
 
51714
 
 
51715
                        /* A -> target register (A, A+1) for call setup
 
51716
                         *      (for DUK_OP_CSREGI, 'a' is indirect)
 
51717
                         * B -> register containing target function (not type checked here)
 
51718
                         */
 
51719
 
 
51720
                        /* FIXME: direct manipulation, or duk_replace_tval() */
 
51721
 
 
51722
                        /* Note: target registers a and a+1 may overlap with DUK__REGP(b).
 
51723
                         * Careful here.
 
51724
                         */
 
51725
 
 
51726
                        if (DUK_DEC_OP(ins) == DUK_OP_CSREGI) {
 
51727
                                duk_tval *tv_ind = DUK__REGP(a);
 
51728
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
51729
                                        DUK__INTERNAL_ERROR("CSREGI target is not a number");
 
51730
                                }
 
51731
                                a = (int) DUK_TVAL_GET_NUMBER(tv_ind);  /* not validated */
 
51732
                        }
 
51733
 
 
51734
                        duk_push_tval(ctx, DUK__REGP(b));
 
51735
                        duk_replace(ctx, a);
 
51736
                        duk_push_undefined(ctx);
 
51737
                        duk_replace(ctx, a+1);
 
51738
                        break;
 
51739
                }
 
51740
 
 
51741
                case DUK_OP_GETVAR: {
 
51742
                        duk_context *ctx = (duk_context *) thr;
 
51743
                        int a = DUK_DEC_A(ins);
 
51744
                        int bc = DUK_DEC_BC(ins);
 
51745
                        duk_tval *tv1;
 
51746
                        duk_hstring *name;
 
51747
 
 
51748
                        tv1 = DUK__CONSTP(bc);
 
51749
                        if (!DUK_TVAL_IS_STRING(tv1)) {
 
51750
                                DUK_DDDPRINT("GETVAR not a string: %!T", tv1);
 
51751
                                DUK__INTERNAL_ERROR("GETVAR name not a string");
 
51752
                        }
 
51753
                        name = DUK_TVAL_GET_STRING(tv1);
 
51754
                        DUK_DDDPRINT("GETVAR: '%!O'", name);
 
51755
                        (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/);  /* -> [... val this] */
 
51756
 
 
51757
                        duk_pop(ctx);  /* 'this' binding is not needed here */
 
51758
                        duk_replace(ctx, a);
 
51759
                        break;
 
51760
                }
 
51761
 
 
51762
                case DUK_OP_PUTVAR: {
 
51763
                        int a = DUK_DEC_A(ins);
 
51764
                        int bc = DUK_DEC_BC(ins);
 
51765
                        duk_tval *tv1;
 
51766
                        duk_hstring *name;
 
51767
 
 
51768
                        tv1 = DUK__CONSTP(bc);
 
51769
                        if (!DUK_TVAL_IS_STRING(tv1)) {
 
51770
                                DUK__INTERNAL_ERROR("PUTVAR name not a string");
 
51771
                        }
 
51772
                        name = DUK_TVAL_GET_STRING(tv1);
 
51773
 
 
51774
                        /* FIXME: putvar takes a duk_tval pointer, which is awkward and
 
51775
                         * should be reworked.
 
51776
                         */
 
51777
 
 
51778
                        tv1 = DUK__REGP(a);  /* val */
 
51779
                        duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
 
51780
                        break;
 
51781
                }
 
51782
 
 
51783
                case DUK_OP_DECLVAR: {
 
51784
                        duk_context *ctx = (duk_context *) thr;
 
51785
                        int a = DUK_DEC_A(ins);
 
51786
                        int b = DUK_DEC_B(ins);
 
51787
                        int c = DUK_DEC_C(ins);
 
51788
                        duk_tval *tv1;
 
51789
                        duk_hstring *name;
 
51790
                        int prop_flags;
 
51791
                        int is_func_decl;
 
51792
                        int flag_undef_value;
 
51793
                        int flag_func_decl;
 
51794
 
 
51795
                        tv1 = DUK__REGCONSTP(b);
 
51796
                        if (!DUK_TVAL_IS_STRING(tv1)) {
 
51797
                                DUK__INTERNAL_ERROR("DECLVAR name not a string");
 
51798
                        }
 
51799
                        name = DUK_TVAL_GET_STRING(tv1);
 
51800
 
 
51801
                        flag_undef_value = a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
 
51802
                        flag_func_decl = a & DUK_BC_DECLVAR_FLAG_FUNC_DECL;
 
51803
 
 
51804
                        /* FIXME: declvar takes an duk_tval pointer, which is awkward and
 
51805
                         * should be reworked.
 
51806
                         */
 
51807
 
 
51808
                        /* Compiler is responsible for selecting property flags (configurability,
 
51809
                         * writability, etc).
 
51810
                         */
 
51811
                        prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
 
51812
                        is_func_decl = flag_func_decl;
 
51813
 
 
51814
                        if (flag_undef_value) {
 
51815
                                duk_push_undefined(ctx);
 
51816
                        } else {
 
51817
                                duk_push_tval(ctx, DUK__REGCONSTP(c));
 
51818
                        }
 
51819
                        tv1 = duk_get_tval(ctx, -1);
 
51820
 
 
51821
                        if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
 
51822
                                /* already declared, must update binding value */
 
51823
                                tv1 = duk_get_tval(ctx, -1);
 
51824
                                duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
 
51825
                        }
 
51826
 
 
51827
                        duk_pop(ctx);
 
51828
                        break;
 
51829
                }
 
51830
 
 
51831
                case DUK_OP_DELVAR: {
 
51832
                        duk_context *ctx = (duk_context *) thr;
 
51833
                        int a = DUK_DEC_A(ins);
 
51834
                        int b = DUK_DEC_B(ins);
 
51835
                        duk_tval *tv1;
 
51836
                        duk_hstring *name;
 
51837
                        int rc;
 
51838
 
 
51839
                        tv1 = DUK__REGCONSTP(b);
 
51840
                        if (!DUK_TVAL_IS_STRING(tv1)) {
 
51841
                                DUK__INTERNAL_ERROR("DELVAR name not a string");
 
51842
                        }
 
51843
                        name = DUK_TVAL_GET_STRING(tv1);
 
51844
                        DUK_DDDPRINT("DELVAR '%!O'", name);
 
51845
                        rc = duk_js_delvar_activation(thr, act, name);
 
51846
 
 
51847
                        duk_push_boolean(ctx, rc);
 
51848
                        duk_replace(ctx, a);
 
51849
                        break;
 
51850
                }
 
51851
 
 
51852
                case DUK_OP_CSVAR:
 
51853
                case DUK_OP_CSVARI: {
 
51854
                        /* 'this' value:
 
51855
                         * E5 Section 6.b.i
 
51856
                         *
 
51857
                         * The only (standard) case where the 'this' binding is non-null is when
 
51858
                         *   (1) the variable is found in an object environment record, and
 
51859
                         *   (2) that object environment record is a 'with' block.
 
51860
                         *
 
51861
                         */
 
51862
 
 
51863
                        duk_context *ctx = (duk_context *) thr;
 
51864
                        int a = DUK_DEC_A(ins);
 
51865
                        int b = DUK_DEC_B(ins);
 
51866
                        duk_tval *tv1;
 
51867
                        duk_hstring *name;
 
51868
 
 
51869
                        tv1 = DUK__REGCONSTP(b);
 
51870
                        if (!DUK_TVAL_IS_STRING(tv1)) {
 
51871
                                DUK__INTERNAL_ERROR("CSVAR name not a string");
 
51872
                        }
 
51873
                        name = DUK_TVAL_GET_STRING(tv1);
 
51874
                        (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/);  /* -> [... val this] */
 
51875
 
 
51876
                        /* Note: target registers a and a+1 may overlap with DUK__REGCONSTP(b)
 
51877
                         * and DUK__REGCONSTP(c).  Careful here.
 
51878
                         */
 
51879
 
 
51880
                        if (DUK_DEC_OP(ins) == DUK_OP_CSVARI) {
 
51881
                                duk_tval *tv_ind = DUK__REGP(a);
 
51882
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
51883
                                        DUK__INTERNAL_ERROR("CSVARI target is not a number");
 
51884
                                }
 
51885
                                a = (int) DUK_TVAL_GET_NUMBER(tv_ind);  /* not validated */
 
51886
                        }
 
51887
 
 
51888
                        duk_replace(ctx, a+1);  /* 'this' binding */
 
51889
                        duk_replace(ctx, a);    /* variable value (function, we hope, not checked here) */
 
51890
                        break;
 
51891
                }
 
51892
 
 
51893
                case DUK_OP_CLOSURE: {
 
51894
                        duk_context *ctx = (duk_context *) thr;
 
51895
                        int a = DUK_DEC_A(ins);
 
51896
                        int bc = DUK_DEC_BC(ins);
 
51897
                        duk_hobject *fun_temp;
 
51898
 
 
51899
                        /* A -> target reg
 
51900
                         * BC -> inner function index
 
51901
                         */
 
51902
 
 
51903
                        DUK_DDDPRINT("CLOSURE to target register %d, fnum %d (count %d)",
 
51904
                                     a, bc, DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(fun));
 
51905
 
 
51906
                        DUK_ASSERT(bc >= 0);
 
51907
                        DUK_ASSERT(bc < (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(fun));
 
51908
                        fun_temp = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(fun)[bc];
 
51909
                        DUK_ASSERT(fun_temp != NULL);
 
51910
                        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(fun_temp));
 
51911
 
 
51912
                        DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O", (void *) fun_temp, fun_temp);
 
51913
 
 
51914
                        if (act->lex_env == NULL) {
 
51915
                                DUK_ASSERT(act->var_env == NULL);
 
51916
                                duk_js_init_activation_environment_records_delayed(thr, act);
 
51917
                        }
 
51918
                        DUK_ASSERT(act->lex_env != NULL);
 
51919
                        DUK_ASSERT(act->var_env != NULL);
 
51920
 
 
51921
                        /* functions always have a NEWENV flag, i.e. they get a
 
51922
                         * new variable declaration environment, so only lex_env
 
51923
                         * matters here.
 
51924
                         */
 
51925
                        duk_js_push_closure(thr,
 
51926
                                            (duk_hcompiledfunction *) fun_temp,
 
51927
                                            act->var_env,
 
51928
                                            act->lex_env);
 
51929
                        duk_replace(ctx, a);
 
51930
 
 
51931
                        break;
 
51932
                }
 
51933
 
 
51934
                case DUK_OP_GETPROP: {
 
51935
                        duk_context *ctx = (duk_context *) thr;
 
51936
                        int a = DUK_DEC_A(ins);
 
51937
                        int b = DUK_DEC_B(ins);
 
51938
                        int c = DUK_DEC_C(ins);
 
51939
                        duk_tval *tv_obj;
 
51940
                        duk_tval *tv_key;
 
51941
                        int rc;
 
51942
 
 
51943
                        /* A -> target reg
 
51944
                         * B -> object reg/const (may be const e.g. in "'foo'[1]")
 
51945
                         * C -> key reg/const
 
51946
                         */
 
51947
 
 
51948
                        tv_obj = DUK__REGCONSTP(b);
 
51949
                        tv_key = DUK__REGCONSTP(c);
 
51950
                        DUK_DDDPRINT("GETPROP: a=%d obj=%!T, key=%!T", a, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
51951
                        rc = duk_hobject_getprop(thr, tv_obj, tv_key);  /* -> [val] */
 
51952
                        DUK_UNREF(rc);  /* ignore */
 
51953
                        DUK_DDDPRINT("GETPROP --> %!T", duk_get_tval(ctx, -1));
 
51954
                        tv_obj = NULL;  /* invalidated */
 
51955
                        tv_key = NULL;  /* invalidated */
 
51956
 
 
51957
                        duk_replace(ctx, a);    /* val */
 
51958
                        break;
 
51959
                }
 
51960
 
 
51961
                case DUK_OP_PUTPROP: {
 
51962
                        int a = DUK_DEC_A(ins);
 
51963
                        int b = DUK_DEC_B(ins);
 
51964
                        int c = DUK_DEC_C(ins);
 
51965
                        duk_tval *tv_obj;
 
51966
                        duk_tval *tv_key;
 
51967
                        duk_tval *tv_val;
 
51968
                        int rc;
 
51969
 
 
51970
                        /* A -> object reg
 
51971
                         * B -> key reg/const
 
51972
                         * C -> value reg/const
 
51973
                         *
 
51974
                         * Note: intentional difference to register arrangement
 
51975
                         * of e.g. GETPROP; 'A' must contain a register-only value.
 
51976
                         */
 
51977
 
 
51978
                        tv_obj = DUK__REGP(a);
 
51979
                        tv_key = DUK__REGCONSTP(b);
 
51980
                        tv_val = DUK__REGCONSTP(c);
 
51981
                        DUK_DDDPRINT("PUTPROP: obj=%!T, key=%!T, val=%!T", DUK__REGP(a), DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
51982
                        rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
 
51983
                        DUK_UNREF(rc);  /* ignore */
 
51984
                        DUK_DDDPRINT("PUTPROP --> obj=%!T, key=%!T, val=%!T", DUK__REGP(a), DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
51985
                        tv_obj = NULL;  /* invalidated */
 
51986
                        tv_key = NULL;  /* invalidated */
 
51987
                        tv_val = NULL;  /* invalidated */
 
51988
 
 
51989
                        break;
 
51990
                }
 
51991
 
 
51992
                case DUK_OP_DELPROP: {
 
51993
                        duk_context *ctx = (duk_context *) thr;
 
51994
                        int a = DUK_DEC_A(ins);
 
51995
                        int b = DUK_DEC_B(ins);
 
51996
                        int c = DUK_DEC_C(ins);
 
51997
                        duk_tval *tv_obj;
 
51998
                        duk_tval *tv_key;
 
51999
                        int rc;
 
52000
 
 
52001
                        /* A -> result reg
 
52002
                         * B -> object reg
 
52003
                         * C -> key reg/const
 
52004
                         */
 
52005
 
 
52006
                        tv_obj = DUK__REGP(b);
 
52007
                        tv_key = DUK__REGCONSTP(c);
 
52008
                        rc = duk_hobject_delprop(thr, tv_obj, tv_key, DUK__STRICT());
 
52009
                        tv_obj = NULL;  /* invalidated */
 
52010
                        tv_key = NULL;  /* invalidated */
 
52011
 
 
52012
                        duk_push_boolean(ctx, rc);
 
52013
                        duk_replace(ctx, a);    /* result */
 
52014
                        break;
 
52015
                }
 
52016
 
 
52017
                case DUK_OP_CSPROP:
 
52018
                case DUK_OP_CSPROPI: {
 
52019
                        duk_context *ctx = (duk_context *) thr;
 
52020
                        int a = DUK_DEC_A(ins);
 
52021
                        int b = DUK_DEC_B(ins);
 
52022
                        int c = DUK_DEC_C(ins);
 
52023
                        duk_tval *tv_obj;
 
52024
                        duk_tval *tv_key;
 
52025
                        int rc;
 
52026
 
 
52027
                        /* E5 Section 11.2.3, step 6.a.i */
 
52028
                        /* E5 Section 10.4.3 */
 
52029
 
 
52030
                        /* FIXME: allow object to be a const, e.g. in 'foo'.toString() */
 
52031
 
 
52032
                        tv_obj = DUK__REGP(b);
 
52033
                        tv_key = DUK__REGCONSTP(c);
 
52034
                        rc = duk_hobject_getprop(thr, tv_obj, tv_key);  /* -> [val] */
 
52035
                        DUK_UNREF(rc);  /* unused */
 
52036
                        tv_obj = NULL;  /* invalidated */
 
52037
                        tv_key = NULL;  /* invalidated */
 
52038
 
 
52039
                        /* Note: target registers a and a+1 may overlap with DUK__REGP(b)
 
52040
                         * and DUK__REGCONSTP(c).  Careful here.
 
52041
                         */
 
52042
 
 
52043
                        if (DUK_DEC_OP(ins) == DUK_OP_CSPROPI) {
 
52044
                                duk_tval *tv_ind = DUK__REGP(a);
 
52045
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
52046
                                        DUK__INTERNAL_ERROR("CSPROPI target is not a number");
 
52047
                                }
 
52048
                                a = (int) DUK_TVAL_GET_NUMBER(tv_ind);  /* not validated */
 
52049
                        }
 
52050
 
 
52051
                        duk_push_tval(ctx, DUK__REGP(b));  /* [ ... val obj ] */
 
52052
                        duk_replace(ctx, a+1);        /* 'this' binding */
 
52053
                        duk_replace(ctx, a);          /* val */
 
52054
                        break;
 
52055
                }
 
52056
 
 
52057
                case DUK_OP_ADD:
 
52058
                case DUK_OP_SUB:
 
52059
                case DUK_OP_MUL:
 
52060
                case DUK_OP_DIV:
 
52061
                case DUK_OP_MOD: {
 
52062
                        int a = DUK_DEC_A(ins);
 
52063
                        int b = DUK_DEC_B(ins);
 
52064
                        int c = DUK_DEC_C(ins);
 
52065
                        int op = DUK_DEC_OP(ins);
 
52066
 
 
52067
                        if (op == DUK_OP_ADD) {
 
52068
                                /*
 
52069
                                 *  Handling DUK_OP_ADD this way is more compact (experimentally)
 
52070
                                 *  than a separate case with separate argument decoding.
 
52071
                                 */
 
52072
                                duk__vm_arith_add(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a);
 
52073
                        } else {
 
52074
                                duk__vm_arith_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
 
52075
                        }
 
52076
                        break;
 
52077
                }
 
52078
 
 
52079
                case DUK_OP_BAND:
 
52080
                case DUK_OP_BOR:
 
52081
                case DUK_OP_BXOR:
 
52082
                case DUK_OP_BASL:
 
52083
                case DUK_OP_BLSR:
 
52084
                case DUK_OP_BASR: {
 
52085
                        int a = DUK_DEC_A(ins);
 
52086
                        int b = DUK_DEC_B(ins);
 
52087
                        int c = DUK_DEC_C(ins);
 
52088
                        int op = DUK_DEC_OP(ins);
 
52089
 
 
52090
                        duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
 
52091
                        break;
 
52092
                }
 
52093
 
 
52094
                case DUK_OP_BNOT: {
 
52095
                        int a = DUK_DEC_A(ins);
 
52096
                        int b = DUK_DEC_B(ins);
 
52097
 
 
52098
                        duk__vm_bitwise_not(thr, DUK__REGCONSTP(b), a);
 
52099
                        break;
 
52100
                }
 
52101
 
 
52102
                case DUK_OP_LNOT: {
 
52103
                        int a = DUK_DEC_A(ins);
 
52104
                        int b = DUK_DEC_B(ins);
 
52105
 
 
52106
                        duk__vm_logical_not(thr, DUK__REGCONSTP(b), DUK__REGP(a));
 
52107
                        break;
 
52108
                }
 
52109
 
 
52110
                case DUK_OP_EQ:
 
52111
                case DUK_OP_NEQ: {
 
52112
                        duk_context *ctx = (duk_context *) thr;
 
52113
                        int a = DUK_DEC_A(ins);
 
52114
                        int b = DUK_DEC_B(ins);
 
52115
                        int c = DUK_DEC_C(ins);
 
52116
                        int tmp;
 
52117
 
 
52118
                        /* E5 Sections 11.9.1, 11.9.3 */
 
52119
                        tmp = duk_js_equals(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
52120
                        if (DUK_DEC_OP(ins) == DUK_OP_NEQ) {
 
52121
                                tmp = !tmp;
 
52122
                        }
 
52123
                        duk_push_boolean(ctx, tmp);
 
52124
                        duk_replace(ctx, a);
 
52125
                        break;
 
52126
                }
 
52127
 
 
52128
                case DUK_OP_SEQ:
 
52129
                case DUK_OP_SNEQ: {
 
52130
                        duk_context *ctx = (duk_context *) thr;
 
52131
                        int a = DUK_DEC_A(ins);
 
52132
                        int b = DUK_DEC_B(ins);
 
52133
                        int c = DUK_DEC_C(ins);
 
52134
                        int tmp;
 
52135
 
 
52136
                        /* E5 Sections 11.9.1, 11.9.3 */
 
52137
                        tmp = duk_js_strict_equals(DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
52138
                        if (DUK_DEC_OP(ins) == DUK_OP_SNEQ) {
 
52139
                                tmp = !tmp;
 
52140
                        }
 
52141
                        duk_push_boolean(ctx, tmp);
 
52142
                        duk_replace(ctx, a);
 
52143
                        break;
 
52144
                }
 
52145
 
 
52146
                /* Note: combining comparison ops must be done carefully because
 
52147
                 * of uncomparable values (NaN): it's not necessarily true that
 
52148
                 * (x >= y) === !(x < y).  Also, evaluation order matters, and
 
52149
                 * although it would only seem to affect the compiler this is
 
52150
                 * actually not the case, because there are also run-time coercions
 
52151
                 * of the arguments (with potential side effects).
 
52152
                 *
 
52153
                 * FIXME: can be combined; check code size.
 
52154
                 */
 
52155
 
 
52156
                case DUK_OP_GT: {
 
52157
                        duk_context *ctx = (duk_context *) thr;
 
52158
                        int a = DUK_DEC_A(ins);
 
52159
                        int b = DUK_DEC_B(ins);
 
52160
                        int c = DUK_DEC_C(ins);
 
52161
                        int tmp;
 
52162
 
 
52163
                        /* x > y  -->  y < x */
 
52164
                        tmp = duk_js_compare_helper(thr,
 
52165
                                                    DUK__REGCONSTP(c),  /* y */
 
52166
                                                    DUK__REGCONSTP(b),  /* x */
 
52167
                                                    0);                 /* flags */
 
52168
 
 
52169
                        duk_push_boolean(ctx, tmp);
 
52170
                        duk_replace(ctx, a);
 
52171
                        break;
 
52172
                }
 
52173
 
 
52174
                case DUK_OP_GE: {
 
52175
                        duk_context *ctx = (duk_context *) thr;
 
52176
                        int a = DUK_DEC_A(ins);
 
52177
                        int b = DUK_DEC_B(ins);
 
52178
                        int c = DUK_DEC_C(ins);
 
52179
                        int tmp;
 
52180
 
 
52181
                        /* x >= y  -->  not (x < y) */
 
52182
                        tmp = duk_js_compare_helper(thr,
 
52183
                                                    DUK__REGCONSTP(b),  /* x */
 
52184
                                                    DUK__REGCONSTP(c),  /* y */
 
52185
                                                    DUK_COMPARE_FLAG_EVAL_LEFT_FIRST |
 
52186
                                                    DUK_COMPARE_FLAG_NEGATE);  /* flags */
 
52187
 
 
52188
                        duk_push_boolean(ctx, tmp);
 
52189
                        duk_replace(ctx, a);
 
52190
                        break;
 
52191
                }
 
52192
 
 
52193
                case DUK_OP_LT: {
 
52194
                        duk_context *ctx = (duk_context *) thr;
 
52195
                        int a = DUK_DEC_A(ins);
 
52196
                        int b = DUK_DEC_B(ins);
 
52197
                        int c = DUK_DEC_C(ins);
 
52198
                        int tmp;
 
52199
 
 
52200
                        /* x < y */
 
52201
                        tmp = duk_js_compare_helper(thr,
 
52202
                                                    DUK__REGCONSTP(b),  /* x */
 
52203
                                                    DUK__REGCONSTP(c),  /* y */
 
52204
                                                    DUK_COMPARE_FLAG_EVAL_LEFT_FIRST);  /* flags */
 
52205
 
 
52206
                        duk_push_boolean(ctx, tmp);
 
52207
                        duk_replace(ctx, a);
 
52208
                        break;
 
52209
                }
 
52210
 
 
52211
                case DUK_OP_LE: {
 
52212
                        duk_context *ctx = (duk_context *) thr;
 
52213
                        int a = DUK_DEC_A(ins);
 
52214
                        int b = DUK_DEC_B(ins);
 
52215
                        int c = DUK_DEC_C(ins);
 
52216
                        int tmp;
 
52217
 
 
52218
                        /* x <= y  -->  not (x > y)  -->  not (y < x) */
 
52219
                        tmp = duk_js_compare_helper(thr,
 
52220
                                                    DUK__REGCONSTP(c),  /* y */
 
52221
                                                    DUK__REGCONSTP(b),  /* x */
 
52222
                                                    DUK_COMPARE_FLAG_NEGATE);  /* flags */
 
52223
 
 
52224
                        duk_push_boolean(ctx, tmp);
 
52225
                        duk_replace(ctx, a);
 
52226
                        break;
 
52227
                }
 
52228
 
 
52229
                case DUK_OP_IF: {
 
52230
                        int a = DUK_DEC_A(ins);
 
52231
                        int b = DUK_DEC_B(ins);
 
52232
                        int tmp;
 
52233
 
 
52234
                        tmp = duk_js_toboolean(DUK__REGCONSTP(b));
 
52235
                        if (tmp == a) {
 
52236
                                /* if boolean matches A, skip next inst */
 
52237
                                act->pc++;
 
52238
                        } else {
 
52239
                                ;
 
52240
                        }
 
52241
                        break;
 
52242
                }
 
52243
 
 
52244
                case DUK_OP_INSTOF: {
 
52245
                        duk_context *ctx = (duk_context *) thr;
 
52246
                        int a = DUK_DEC_A(ins);
 
52247
                        int b = DUK_DEC_B(ins);
 
52248
                        int c = DUK_DEC_C(ins);
 
52249
                        int tmp;
 
52250
 
 
52251
                        tmp = duk_js_instanceof(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
52252
                        duk_push_boolean(ctx, tmp);
 
52253
                        duk_replace(ctx, a);
 
52254
                        break;
 
52255
                }
 
52256
 
 
52257
                case DUK_OP_IN: {
 
52258
                        duk_context *ctx = (duk_context *) thr;
 
52259
                        int a = DUK_DEC_A(ins);
 
52260
                        int b = DUK_DEC_B(ins);
 
52261
                        int c = DUK_DEC_C(ins);
 
52262
                        int tmp;
 
52263
 
 
52264
                        tmp = duk_js_in(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
 
52265
                        duk_push_boolean(ctx, tmp);
 
52266
                        duk_replace(ctx, a);
 
52267
                        break;
 
52268
                }
 
52269
 
 
52270
                case DUK_OP_JUMP: {
 
52271
                        int abc = DUK_DEC_ABC(ins);
 
52272
 
 
52273
                        act->pc += abc - DUK_BC_JUMP_BIAS;
 
52274
                        break;
 
52275
                }
 
52276
 
 
52277
                case DUK_OP_RETURN: {
 
52278
                        duk_context *ctx = (duk_context *) thr;
 
52279
                        int a = DUK_DEC_A(ins);
 
52280
                        int b = DUK_DEC_B(ins);
 
52281
                        /* int c = DUK_DEC_C(ins); */
 
52282
 
 
52283
                        /* A -> flags
 
52284
                         * B -> return value reg/const
 
52285
                         * C -> currently unused: FIXME
 
52286
                         */
 
52287
 
 
52288
                        /* FIXME: fast return not implemented, always do a slow return now */
 
52289
                        if (a & DUK_BC_RETURN_FLAG_FAST && 0 /*FIXME*/) {
 
52290
                                /* fast return: no TCF catchers (but may have e.g. labels) */
 
52291
                                DUK__INTERNAL_ERROR("FIXME: fast return unimplemented");
 
52292
                        } else {
 
52293
                                /* slow return */
 
52294
 
 
52295
                                DUK_DDDPRINT("SLOWRETURN a=%d b=%d", a, b);
 
52296
 
 
52297
                                if (a & DUK_BC_RETURN_FLAG_HAVE_RETVAL) {
 
52298
                                        duk_push_tval(ctx, DUK__REGCONSTP(b));
 
52299
                                } else {
 
52300
                                        duk_push_undefined(ctx);
 
52301
                                }
 
52302
 
 
52303
                                duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_RETURN);
 
52304
 
 
52305
                                DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* in bytecode executor, should always be set */
 
52306
                                duk_err_longjmp(thr);
 
52307
                                DUK_UNREACHABLE();
 
52308
                        }
 
52309
                        break;
 
52310
                }
 
52311
 
 
52312
                case DUK_OP_CALL:
 
52313
                case DUK_OP_CALLI: {
 
52314
                        duk_context *ctx = (duk_context *) thr;
 
52315
                        int a = DUK_DEC_A(ins);
 
52316
                        int b = DUK_DEC_B(ins);
 
52317
                        int c = DUK_DEC_C(ins);
 
52318
                        int call_flags;
 
52319
                        int flag_tailcall;
 
52320
                        int flag_evalcall;
 
52321
                        duk_tval *tv_func;
 
52322
                        duk_hobject *obj_func;        /* target function, possibly a bound function */
 
52323
                        duk_hobject *obj_final_func;  /* final target function, non-bound function */
 
52324
 
 
52325
                        /* A -> flags
 
52326
                         * B -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
 
52327
                         *      (for DUK_OP_CALLI, 'b' is indirect)
 
52328
                         * C -> nargs
 
52329
                         */
 
52330
 
 
52331
                        /* these are not necessarily 0 or 1 (may be other non-zero), that's ok */
 
52332
                        flag_tailcall = (a & DUK_BC_CALL_FLAG_TAILCALL);
 
52333
                        flag_evalcall = (a & DUK_BC_CALL_FLAG_EVALCALL);
 
52334
 
 
52335
                        if (DUK_DEC_OP(ins) == DUK_OP_CALLI) {
 
52336
                                duk_tval *tv_ind = DUK__REGP(b);
 
52337
                                if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
52338
                                        DUK__INTERNAL_ERROR("CALLI target is not a number");
 
52339
                                }
 
52340
                                b = (int) DUK_TVAL_GET_NUMBER(tv_ind);  /* not validated */
 
52341
                        }
 
52342
 
 
52343
                        tv_func = DUK__REGP(b);
 
52344
                        if (!DUK_TVAL_IS_OBJECT(tv_func)) {
 
52345
                                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "call target not an object");
 
52346
                        }
 
52347
                        obj_func = DUK_TVAL_GET_OBJECT(tv_func);
 
52348
 
 
52349
                        /*
 
52350
                         *  To determine whether to use an optimized Ecmascript-to-Ecmascript
 
52351
                         *  call, we need to know whether the final, non-bound function is an
 
52352
                         *  Ecmascript function.  We need to follow the "bound" chain to do that;
 
52353
                         *  the "bound" chain will be followed for the second time when calling.
 
52354
                         *  This overhead only affects bound functions (in particular, helper
 
52355
                         *  functions should not be called if the immediate target function is
 
52356
                         *  not bound).
 
52357
                         * 
 
52358
                         *  Even so, this awkward solution could be avoided by e.g. replicating
 
52359
                         *  final, non-bound target function flags to the bound function objects
 
52360
                         *  (so that a bound function would e.g. have both a "BOUND" flag and
 
52361
                         *  a "COMPILEDFUNCTION" flag).  Also, bound functions could also keep
 
52362
                         *  a direct reference to the final non-bound function ("shortcut").
 
52363
                         */
 
52364
 
 
52365
                        if (DUK_HOBJECT_HAS_BOUND(obj_func)) {
 
52366
                                obj_final_func = duk__find_nonbound_function(thr, obj_func);
 
52367
                        } else {
 
52368
                                obj_final_func = obj_func;
 
52369
                        }
 
52370
 
 
52371
                        duk_set_top(ctx, b + c + 2);   /* [ ... func this arg1 ... argN ] */
 
52372
 
 
52373
                        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(obj_final_func)) {
 
52374
                                /*
 
52375
                                 *  Ecmascript-to-Ecmascript call: avoid C recursion
 
52376
                                 *  by being clever.
 
52377
                                 */
 
52378
 
 
52379
                                /* Compared to duk_handle_call():
 
52380
                                 *   - protected call: never
 
52381
                                 *   - ignore recursion limit: never
 
52382
                                 */
 
52383
 
 
52384
                                /* FIXME: optimize flag handling, by coordinating with bytecode */
 
52385
                                call_flags = 0;
 
52386
                                if (flag_tailcall) {
 
52387
                                        call_flags |= DUK_CALL_FLAG_IS_TAILCALL;
 
52388
                                }
 
52389
 
 
52390
                                duk_handle_ecma_call_setup(thr,
 
52391
                                                           c,              /* num_stack_args */
 
52392
                                                           call_flags);    /* call_flags */
 
52393
 
 
52394
                                /* restart execution -> starts executing new function */
 
52395
                                goto restart_execution;
 
52396
                        } else {
 
52397
                                /*
 
52398
                                 *  Other cases, use C recursion.
 
52399
                                 *
 
52400
                                 *  If a tailcall was requested, we must handle it inline as there will
 
52401
                                 *  be no RETURN in the bytecode.  The RETURN is always a fast one, as
 
52402
                                 *  the compiler won't emit a tailcall otherwise.
 
52403
                                 *
 
52404
                                 *  Direct eval call: (1) call target (before following bound function
 
52405
                                 *  chain) is the built-in eval() function, and (2) call was made with
 
52406
                                 *  the identifier 'eval'.
 
52407
                                 */
 
52408
 
 
52409
                                call_flags = 0;  /* not protected, respect reclimit, not constructor */
 
52410
 
 
52411
                                if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj_func) &&
 
52412
                                    ((duk_hnativefunction *) obj_func)->func == duk_bi_global_object_eval) {
 
52413
                                        if (flag_evalcall) {
 
52414
                                                DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval");
 
52415
                                                call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
 
52416
                                        } else {
 
52417
                                                DUK_DDDPRINT("call target is eval, call identifier was not 'eval' -> indirect eval");
 
52418
                                        }
 
52419
                                }
 
52420
 
 
52421
                                duk_handle_call(thr,
 
52422
                                                c,            /* num_stack_args */
 
52423
                                                call_flags);  /* call_flags */
 
52424
 
 
52425
                                /* FIXME: who should restore? */
 
52426
                                duk_require_stack_top(ctx, fun->nregs);  /* may have shrunk by inner calls, must recheck */
 
52427
                                duk_set_top(ctx, fun->nregs);
 
52428
 
 
52429
                                if (flag_tailcall) {
 
52430
                                        DUK_DDDPRINT("tailcall requested but needed to do a recursive call "
 
52431
                                                     "instead; now perform a fast return");
 
52432
                                        DUK_DDDPRINT("FIXME: SLOW RETURN NOW");
 
52433
 
 
52434
                                        duk_dup(ctx, b);
 
52435
                                        duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_RETURN);
 
52436
 
 
52437
                                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* in bytecode executor, should always be set */
 
52438
                                        duk_err_longjmp(thr);
 
52439
                                        DUK_UNREACHABLE();
 
52440
                                }
 
52441
 
 
52442
                                /* must reinit setjmp() catchpoint */  /* FIXME: why */
 
52443
                                goto reset_setjmp_catchpoint;
 
52444
                        }
 
52445
 
 
52446
                        DUK_UNREACHABLE();
 
52447
                        break;
 
52448
                }
 
52449
 
 
52450
                case DUK_OP_LABEL: {
 
52451
                        duk_catcher *cat;
 
52452
                        int abc = DUK_DEC_ABC(ins);
 
52453
 
 
52454
                        /* allocate catcher and populate it (should be atomic) */
 
52455
 
 
52456
                        duk_hthread_catchstack_grow(thr);
 
52457
                        cat = &thr->catchstack[thr->catchstack_top];
 
52458
                        thr->catchstack_top++;
 
52459
 
 
52460
                        cat->flags = DUK_CAT_TYPE_LABEL | (abc << DUK_CAT_LABEL_SHIFT);
 
52461
                        cat->callstack_index = thr->callstack_top - 1;
 
52462
                        cat->pc_base = act->pc;  /* pre-incremented, points to first jump slot */
 
52463
                        cat->idx_base = 0;  /* unused for label */
 
52464
                        cat->h_varname = NULL;
 
52465
 
 
52466
                        DUK_DDDPRINT("LABEL catcher: flags=0x%08x, callstack_index=%d, pc_base=%d, idx_base=%d, h_varname=%!O, label_id=%d",
 
52467
                                     cat->flags, cat->callstack_index, cat->pc_base, cat->idx_base, cat->h_varname,
 
52468
                                     DUK_CAT_GET_LABEL(cat));
 
52469
 
 
52470
                        act->pc += 2;  /* skip jump slots */
 
52471
                        break;
 
52472
                }
 
52473
 
 
52474
                case DUK_OP_ENDLABEL: {
 
52475
                        duk_catcher *cat;
 
52476
#if defined(DUK_USE_DDDEBUG) || defined(DUK_USE_ASSERTIONS)
 
52477
                        duk_int_t abc = DUK_DEC_ABC(ins);
 
52478
                        DUK_DDDPRINT("ENDLABEL %d", (int) abc);
 
52479
#endif
 
52480
 
 
52481
                        DUK_ASSERT(thr->catchstack_top >= 1);
 
52482
 
 
52483
                        cat = &thr->catchstack[thr->catchstack_top - 1];
 
52484
                        DUK_UNREF(cat);
 
52485
                        DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
 
52486
                        DUK_ASSERT((duk_int_t) DUK_CAT_GET_LABEL(cat) == abc);
 
52487
 
 
52488
                        duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
 
52489
                        /* no need to unwind callstack */
 
52490
                        break;
 
52491
                }
 
52492
 
 
52493
                case DUK_OP_BREAK: {
 
52494
                        duk_context *ctx = (duk_context *) thr;
 
52495
                        int abc = DUK_DEC_ABC(ins);
 
52496
 
 
52497
                        /* always the "slow break" variant (longjmp'ing); a "fast break" is
 
52498
                         * simply an DUK_OP_JUMP.
 
52499
                         */
 
52500
 
 
52501
                        DUK_DDDPRINT("BREAK: %d", abc);
 
52502
 
 
52503
                        duk_push_int(ctx, abc);
 
52504
                        duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_BREAK);
 
52505
 
 
52506
                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
 
52507
                        duk_err_longjmp(thr);
 
52508
 
 
52509
                        DUK_UNREACHABLE();
 
52510
                        break;
 
52511
                }
 
52512
 
 
52513
                case DUK_OP_CONTINUE: {
 
52514
                        duk_context *ctx = (duk_context *) thr;
 
52515
                        int abc = DUK_DEC_ABC(ins);
 
52516
 
 
52517
                        /* always the "slow continue" variant (longjmp'ing); a "fast continue" is
 
52518
                         * simply an DUK_OP_JUMP.
 
52519
                         */
 
52520
 
 
52521
                        DUK_DDDPRINT("CONTINUE: %d", abc);
 
52522
 
 
52523
                        duk_push_int(ctx, abc);
 
52524
                        duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_CONTINUE);
 
52525
 
 
52526
                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
 
52527
                        duk_err_longjmp(thr);
 
52528
 
 
52529
                        DUK_UNREACHABLE();
 
52530
                        break;
 
52531
                }
 
52532
 
 
52533
                case DUK_OP_TRYCATCH: {
 
52534
                        duk_context *ctx = (duk_context *) thr;
 
52535
                        duk_catcher *cat;
 
52536
                        duk_tval *tv1;
 
52537
                        int a, b, c;
 
52538
 
 
52539
                        /* A -> flags
 
52540
                         * B -> reg_catch; base register for 2 regs
 
52541
                         * C -> semantics depend on flags: var_name or with_target
 
52542
                         *
 
52543
                         *      If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
 
52544
                         *          C is constant index for catch binding variable name.
 
52545
                         *          Automatic declarative environment is established for
 
52546
                         *          the duration of the 'catch' clause.
 
52547
                         *
 
52548
                         *      If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
 
52549
                         *          C is reg/const index for with 'target value', which
 
52550
                         *          is coerced to an object and then used as a binding
 
52551
                         *          object for an environment record.  The binding is
 
52552
                         *          initialized here, for the 'try' clause.
 
52553
                         *
 
52554
                         * Note that a TRYCATCH generated for a 'with' statement has no
 
52555
                         * catch or finally parts.
 
52556
                         */
 
52557
 
 
52558
                        /* FIXME: side effect handling is quite awkward here */
 
52559
 
 
52560
                        DUK_DDDPRINT("TRYCATCH: reg_catch=%d, var_name/with_target=%d, have_catch=%d, have_finally=%d, catch_binding=%d, with_binding=%d (flags=0x%02x)",
 
52561
                                     DUK_DEC_B(ins),
 
52562
                                     DUK_DEC_C(ins),
 
52563
                                     (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
 
52564
                                     (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
 
52565
                                     (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
 
52566
                                     (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
 
52567
                                     DUK_DEC_A(ins));
 
52568
 
 
52569
                        a = DUK_DEC_A(ins);
 
52570
                        b = DUK_DEC_B(ins);
 
52571
                        c = DUK_DEC_C(ins);
 
52572
 
 
52573
                        DUK_ASSERT(thr->callstack_top >= 1);
 
52574
 
 
52575
                        /* with target must be created first, in case we run out of memory */
 
52576
                        /* FIXME: refactor out? */
 
52577
 
 
52578
                        if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
 
52579
                                DUK_DDDPRINT("need to initialize a with binding object");
 
52580
 
 
52581
                                if (act->lex_env == NULL) {
 
52582
                                        DUK_ASSERT(act->var_env == NULL);
 
52583
                                        DUK_DDDPRINT("delayed environment initialization");
 
52584
 
 
52585
                                        /* must relookup act in case of side effects */
 
52586
                                        duk_js_init_activation_environment_records_delayed(thr, act);
 
52587
                                        act = thr->callstack + thr->callstack_top - 1;
 
52588
                                }
 
52589
                                DUK_ASSERT(act->lex_env != NULL);
 
52590
                                DUK_ASSERT(act->var_env != NULL);
 
52591
 
 
52592
                                (void) duk_push_object_helper(ctx,
 
52593
                                                              DUK_HOBJECT_FLAG_EXTENSIBLE |
 
52594
                                                              DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
 
52595
                                                              -1);  /* no prototype, updated below */
 
52596
 
 
52597
                                duk_push_tval(ctx, DUK__REGCONSTP(c));
 
52598
                                duk_to_object(ctx, -1);
 
52599
                                duk_dup(ctx, -1);
 
52600
 
 
52601
                                /* [ ... env target ] */
 
52602
                                /* [ ... env target target ] */
 
52603
 
 
52604
                                duk_def_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
 
52605
                                duk_def_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);  /* always provideThis=true */
 
52606
 
 
52607
                                /* [ ... env ] */
 
52608
 
 
52609
                                DUK_DDDPRINT("environment for with binding: %!iT", duk_get_tval(ctx, -1));
 
52610
                        }
 
52611
 
 
52612
                        /* allocate catcher and populate it (should be atomic) */
 
52613
 
 
52614
                        duk_hthread_catchstack_grow(thr);
 
52615
                        cat = &thr->catchstack[thr->catchstack_top];
 
52616
                        DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
 
52617
                        thr->catchstack_top++;
 
52618
 
 
52619
                        cat->flags = DUK_CAT_TYPE_TCF;
 
52620
                        cat->h_varname = NULL;
 
52621
 
 
52622
                        if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
 
52623
                                cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
 
52624
                        }
 
52625
                        if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
 
52626
                                cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
 
52627
                        }
 
52628
                        if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
 
52629
                                DUK_DDDPRINT("catch binding flag set to catcher");
 
52630
                                cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
 
52631
                                tv1 = DUK__CONSTP(c);
 
52632
                                DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
 
52633
                                cat->h_varname = DUK_TVAL_GET_STRING(tv1);
 
52634
                        } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
 
52635
                                /* env created above to stack top */
 
52636
                                duk_hobject *new_env;
 
52637
 
 
52638
                                DUK_DDDPRINT("lexenv active flag set to catcher");
 
52639
                                cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
 
52640
 
 
52641
                                DUK_DDDPRINT("activating object env: %!iT", duk_get_tval(ctx, -1));
 
52642
                                DUK_ASSERT(act->lex_env != NULL);
 
52643
                                new_env = duk_get_hobject(ctx, -1);
 
52644
                                DUK_ASSERT(new_env != NULL);
 
52645
 
 
52646
                                act = thr->callstack + thr->callstack_top - 1;  /* relookup (side effects) */
 
52647
                                DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env);
 
52648
 
 
52649
                                act = thr->callstack + thr->callstack_top - 1;  /* relookup (side effects) */
 
52650
                                act->lex_env = new_env;
 
52651
                                DUK_HOBJECT_INCREF(thr, new_env);
 
52652
                                duk_pop(ctx);
 
52653
                        } else {
 
52654
                                ;
 
52655
                        }
 
52656
 
 
52657
                        cat = thr->catchstack + thr->catchstack_top - 1;  /* relookup (side effects) */
 
52658
                        cat->callstack_index = thr->callstack_top - 1;
 
52659
                        cat->pc_base = act->pc;  /* pre-incremented, points to first jump slot */
 
52660
                        cat->idx_base = (int) (thr->valstack_bottom - thr->valstack) + b;
 
52661
 
 
52662
                        DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08x, callstack_index=%d, pc_base=%d, idx_base=%d, h_varname=%!O",
 
52663
                                     cat->flags, cat->callstack_index, cat->pc_base, cat->idx_base, cat->h_varname);
 
52664
 
 
52665
                        act->pc += 2;  /* skip jump slots */
 
52666
                        break;
 
52667
                }
 
52668
 
 
52669
                case DUK_OP_EXTRA: {
 
52670
                        /* FIXME: shared decoding of 'b' and 'c'? */
 
52671
 
 
52672
                        int extraop = DUK_DEC_A(ins);
 
52673
                        switch (extraop) {
 
52674
 
 
52675
                        case DUK_EXTRAOP_NOP: {
 
52676
                                /* nop */
 
52677
                                break;
 
52678
                        }
 
52679
 
 
52680
                        case DUK_EXTRAOP_LDTHIS: {
 
52681
                                /* Note: 'this' may be bound to any value, not just an object */
 
52682
                                int b = DUK_DEC_B(ins);
 
52683
                                duk_tval tv_tmp;
 
52684
                                duk_tval *tv1, *tv2;
 
52685
 
 
52686
                                tv1 = DUK__REGP(b);
 
52687
                                tv2 = thr->valstack_bottom - 1;  /* 'this binding' is just under bottom */
 
52688
                                DUK_ASSERT(tv2 >= thr->valstack);
 
52689
 
 
52690
                                DUK_DDDPRINT("LDTHIS: %!T to r%d", tv2, b);
 
52691
 
 
52692
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52693
                                DUK_TVAL_SET_TVAL(tv1, tv2);
 
52694
                                DUK_TVAL_INCREF(thr, tv1);
 
52695
                                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
52696
                                break;
 
52697
                        }
 
52698
 
 
52699
                        case DUK_EXTRAOP_LDUNDEF: {
 
52700
                                int bc = DUK_DEC_BC(ins);
 
52701
                                duk_tval tv_tmp;
 
52702
                                duk_tval *tv1;
 
52703
 
 
52704
                                tv1 = DUK__REGP(bc);
 
52705
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52706
                                DUK_TVAL_SET_UNDEFINED_ACTUAL(tv1);
 
52707
                                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
52708
                                break;
 
52709
                        }
 
52710
 
 
52711
                        case DUK_EXTRAOP_LDNULL: {
 
52712
                                int bc = DUK_DEC_BC(ins);
 
52713
                                duk_tval tv_tmp;
 
52714
                                duk_tval *tv1;
 
52715
 
 
52716
                                tv1 = DUK__REGP(bc);
 
52717
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52718
                                DUK_TVAL_SET_NULL(tv1);
 
52719
                                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
52720
                                break;
 
52721
                        }
 
52722
 
 
52723
                        case DUK_EXTRAOP_LDTRUE:
 
52724
                        case DUK_EXTRAOP_LDFALSE: {
 
52725
                                int bc = DUK_DEC_BC(ins);
 
52726
                                duk_tval tv_tmp;
 
52727
                                duk_tval *tv1;
 
52728
                                int bval = (extraop == DUK_EXTRAOP_LDTRUE ? 1 : 0);
 
52729
 
 
52730
                                tv1 = DUK__REGP(bc);
 
52731
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52732
                                DUK_TVAL_SET_BOOLEAN(tv1, bval);
 
52733
                                DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
 
52734
                                break;
 
52735
                        }
 
52736
 
 
52737
                        case DUK_EXTRAOP_NEWOBJ: {
 
52738
                                duk_context *ctx = (duk_context *) thr;
 
52739
                                int b = DUK_DEC_B(ins);
 
52740
 
 
52741
                                duk_push_object(ctx);
 
52742
                                duk_replace(ctx, b);
 
52743
                                break;
 
52744
                        }
 
52745
 
 
52746
                        case DUK_EXTRAOP_NEWARR: {
 
52747
                                duk_context *ctx = (duk_context *) thr;
 
52748
                                int b = DUK_DEC_B(ins);
 
52749
 
 
52750
                                duk_push_array(ctx);
 
52751
                                duk_replace(ctx, b);
 
52752
                                break;
 
52753
                        }
 
52754
 
 
52755
                        case DUK_EXTRAOP_SETALEN: {
 
52756
                                int t;
 
52757
                                duk_tval *tv1;
 
52758
                                duk_hobject *h;
 
52759
                                duk_uint32_t len;
 
52760
 
 
52761
                                t = DUK_DEC_B(ins); tv1 = DUK__REGP(t);
 
52762
                                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
 
52763
                                h = DUK_TVAL_GET_OBJECT(tv1);
 
52764
 
 
52765
                                t = DUK_DEC_C(ins); tv1 = DUK__REGP(t);
 
52766
                                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
 
52767
                                len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
 
52768
 
 
52769
                                duk_hobject_set_length(thr, h, len);
 
52770
 
 
52771
                                break;
 
52772
                        }
 
52773
 
 
52774
                        case DUK_EXTRAOP_TYPEOF: {
 
52775
                                duk_context *ctx = (duk_context *) thr;
 
52776
                                int b = DUK_DEC_B(ins);
 
52777
                                int c = DUK_DEC_C(ins);
 
52778
                                duk_push_hstring(ctx, duk_js_typeof(thr, DUK__REGCONSTP(c)));
 
52779
                                duk_replace(ctx, b);
 
52780
                                break;
 
52781
                        }
 
52782
 
 
52783
                        case DUK_EXTRAOP_TYPEOFID: {
 
52784
                                duk_context *ctx = (duk_context *) thr;
 
52785
                                int b = DUK_DEC_B(ins);
 
52786
                                int c = DUK_DEC_C(ins);
 
52787
                                duk_hstring *name;
 
52788
                                duk_tval *tv;
 
52789
 
 
52790
                                /* B -> target register
 
52791
                                 * C -> constant index of identifier name
 
52792
                                 */
 
52793
 
 
52794
                                tv = DUK__REGCONSTP(c);  /* FIXME: this could be a DUK__CONSTP instead */
 
52795
                                DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
 
52796
                                name = DUK_TVAL_GET_STRING(tv);
 
52797
                                if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
 
52798
                                        /* -> [... val this] */
 
52799
                                        tv = duk_get_tval(ctx, -2);
 
52800
                                        duk_push_hstring(ctx, duk_js_typeof(thr, tv));
 
52801
                                        duk_replace(ctx, b);
 
52802
                                        duk_pop_2(ctx);
 
52803
                                } else {
 
52804
                                        /* unresolvable, no stack changes */
 
52805
                                        duk_push_hstring_stridx(ctx, DUK_STRIDX_UNDEFINED);
 
52806
                                        duk_replace(ctx, b);
 
52807
                                }
 
52808
 
 
52809
                                break;
 
52810
                        }
 
52811
 
 
52812
                        case DUK_EXTRAOP_TONUM: {
 
52813
                                duk_context *ctx = (duk_context *) thr;
 
52814
                                int b = DUK_DEC_B(ins);
 
52815
                                int c = DUK_DEC_C(ins);
 
52816
                                duk_dup(ctx, c);
 
52817
                                duk_to_number(ctx, -1);
 
52818
                                duk_replace(ctx, b);
 
52819
                                break;
 
52820
                        }
 
52821
 
 
52822
                        case DUK_EXTRAOP_INITENUM: {
 
52823
                                duk_context *ctx = (duk_context *) thr;
 
52824
                                int b = DUK_DEC_B(ins);
 
52825
                                int c = DUK_DEC_C(ins);
 
52826
 
 
52827
                                /*
 
52828
                                 *  Enumeration semantics come from for-in statement, E5 Section 12.6.4.
 
52829
                                 *  If called with 'null' or 'undefined', this opcode returns 'null' as
 
52830
                                 *  the enumerator, which is special cased in NEXTENUM.  This simplifies
 
52831
                                 *  the compiler part
 
52832
                                 */
 
52833
 
 
52834
                                /* B -> register for writing enumerator object
 
52835
                                 * C -> value to be enumerated (expect a register)
 
52836
                                 */
 
52837
 
 
52838
                                if (duk_is_null_or_undefined(ctx, c)) {
 
52839
                                        duk_push_null(ctx);
 
52840
                                        duk_replace(ctx, b);
 
52841
                                } else {
 
52842
                                        duk_dup(ctx, c);
 
52843
                                        duk_to_object(ctx, -1);
 
52844
                                        duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/);  /* [ ... val ] --> [ ... enum ] */
 
52845
                                        duk_replace(ctx, b);
 
52846
                                }
 
52847
                                break;
 
52848
                        }
 
52849
 
 
52850
                        case DUK_EXTRAOP_NEXTENUM: {
 
52851
                                duk_context *ctx = (duk_context *) thr;
 
52852
                                int b = DUK_DEC_B(ins);
 
52853
                                int c = DUK_DEC_C(ins);
 
52854
 
 
52855
                                /*
 
52856
                                 *  NEXTENUM checks whether the enumerator still has unenumerated
 
52857
                                 *  keys.  If so, the next key is loaded to the target register
 
52858
                                 *  and the next instruction is skipped.  Otherwise the next instruction
 
52859
                                 *  will be executed, jumping out of the enumeration loop.
 
52860
                                 */
 
52861
 
 
52862
                                /* B -> target register for next key
 
52863
                                 * C -> enum register
 
52864
                                 */
 
52865
 
 
52866
                                DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T", duk_get_tval(ctx, b), duk_get_tval(ctx, c));
 
52867
 
 
52868
                                if (duk_is_object(ctx, c)) {
 
52869
                                        /* XXX: assert 'c' is an enumerator */
 
52870
                                        duk_dup(ctx, c);
 
52871
                                        if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
 
52872
                                                /* [ ... enum ] -> [ ... next_key ] */
 
52873
                                                DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ", duk_get_tval(ctx, -1));
 
52874
                                                act->pc++;;
 
52875
                                        } else {
 
52876
                                                /* [ ... enum ] -> [ ... ] */
 
52877
                                                DUK_DDDPRINT("enum finished, execute jump slot");
 
52878
                                                duk_push_undefined(ctx);
 
52879
                                        }
 
52880
                                        duk_replace(ctx, b);
 
52881
                                } else {
 
52882
                                        /* 'null' enumerator case -> behave as with an empty enumerator */
 
52883
                                        DUK_ASSERT(duk_is_null(ctx, c));
 
52884
                                        DUK_DDDPRINT("enum is null, execute jump slot");
 
52885
                                }
 
52886
                                break;                          
 
52887
                        }
 
52888
 
 
52889
                        case DUK_EXTRAOP_INITSET:
 
52890
                        case DUK_EXTRAOP_INITSETI:
 
52891
                        case DUK_EXTRAOP_INITGET:
 
52892
                        case DUK_EXTRAOP_INITGETI: {
 
52893
                                duk_context *ctx = (duk_context *) thr;
 
52894
                                int is_set = (extraop == DUK_EXTRAOP_INITSET || extraop == DUK_EXTRAOP_INITSETI);
 
52895
                                int b = DUK_DEC_B(ins);
 
52896
                                int c = DUK_DEC_C(ins);
 
52897
 
 
52898
                                /* B -> object register
 
52899
                                 * C -> C+0 contains key, C+1 closure (value)
 
52900
                                 */
 
52901
 
 
52902
                                /*
 
52903
                                 *  INITSET/INITGET are only used to initialize object literal keys.
 
52904
                                 *  The compiler ensures that there cannot be a previous data property
 
52905
                                 *  of the same name.  It also ensures that setter and getter can only
 
52906
                                 *  be initialized once (or not at all).
 
52907
                                 */
 
52908
 
 
52909
                                if (extraop == DUK_EXTRAOP_INITSETI || extraop == DUK_EXTRAOP_INITGETI) {
 
52910
                                        duk_tval *tv_ind = DUK__REGP(c);
 
52911
                                        if (!DUK_TVAL_IS_NUMBER(tv_ind)) {
 
52912
                                                DUK__INTERNAL_ERROR("DUK_EXTRAOP_INITSETI/DUK_EXTRAOP_INITGETI target is not a number");
 
52913
                                        }
 
52914
                                        c = (int) DUK_TVAL_GET_NUMBER(tv_ind);
 
52915
                                }
 
52916
 
 
52917
                                /* FIXME: this is now a very unoptimal implementation -- this can be
 
52918
                                 * made very simple by direct manipulation of the object internals,
 
52919
                                 * given the guarantees above.
 
52920
                                 */
 
52921
 
 
52922
                                duk_push_hobject(ctx, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR]);
 
52923
                                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_DEFINE_PROPERTY);
 
52924
                                duk_push_undefined(ctx);
 
52925
                                duk_dup(ctx, b);
 
52926
                                duk_dup(ctx, c + 0);
 
52927
                                duk_push_object(ctx);  /* -> [ Object defineProperty undefined obj key desc ] */
 
52928
 
 
52929
                                duk_push_true(ctx);
 
52930
                                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
 
52931
                                duk_push_true(ctx);
 
52932
                                duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
 
52933
                                duk_dup(ctx, c + 1);
 
52934
                                duk_put_prop_stridx(ctx, -2, (is_set ? DUK_STRIDX_SET : DUK_STRIDX_GET));
 
52935
 
 
52936
                                DUK_DDDPRINT("INITGET/INITSET: obj=%!T, key=%!T, desc=%!T",
 
52937
                                             duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
52938
 
 
52939
                                duk_call_method(ctx, 3);  /* -> [ Object res ] */
 
52940
                                duk_pop_2(ctx);
 
52941
 
 
52942
                                DUK_DDDPRINT("INITGET/INITSET AFTER: obj=%!T", duk_get_tval(ctx, b));
 
52943
                                break;
 
52944
                        }
 
52945
 
 
52946
                        case DUK_EXTRAOP_ENDTRY: {
 
52947
                                duk_catcher *cat;
 
52948
                                duk_tval tv_tmp;
 
52949
                                duk_tval *tv1;
 
52950
 
 
52951
                                DUK_ASSERT(thr->catchstack_top >= 1);
 
52952
                                DUK_ASSERT(thr->callstack_top >= 1);
 
52953
                                DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
 
52954
 
 
52955
                                cat = &thr->catchstack[thr->catchstack_top - 1];
 
52956
 
 
52957
                                DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)");
 
52958
                                DUK_CAT_CLEAR_CATCH_ENABLED(cat);
 
52959
 
 
52960
                                if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
 
52961
                                        DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'");
 
52962
                        
 
52963
                                        tv1 = &thr->valstack[cat->idx_base];
 
52964
                                        DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
 
52965
                                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52966
                                        DUK_TVAL_SET_UNDEFINED_ACTUAL(tv1);
 
52967
                                        DUK_TVAL_DECREF(thr, &tv_tmp);     /* side effects */
 
52968
                                        tv1 = NULL;
 
52969
 
 
52970
                                        tv1 = &thr->valstack[cat->idx_base + 1];
 
52971
                                        DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
 
52972
                                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
52973
                                        DUK_TVAL_SET_NUMBER(tv1, (double) DUK_LJ_TYPE_NORMAL);
 
52974
                                        DUK_TVAL_DECREF(thr, &tv_tmp);     /* side effects */
 
52975
                                        tv1 = NULL;
 
52976
 
 
52977
                                        DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
 
52978
                                } else {
 
52979
                                        DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)");
 
52980
                                        duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
 
52981
                                        /* no need to unwind callstack */
 
52982
                                }
 
52983
 
 
52984
                                act->pc = cat->pc_base + 1;
 
52985
                                break;
 
52986
                        }
 
52987
 
 
52988
                        case DUK_EXTRAOP_ENDCATCH: {
 
52989
                                duk_catcher *cat;
 
52990
                                duk_tval tv_tmp;
 
52991
                                duk_tval *tv1;
 
52992
 
 
52993
                                DUK_ASSERT(thr->catchstack_top >= 1);
 
52994
                                DUK_ASSERT(thr->callstack_top >= 1);
 
52995
                                DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
 
52996
 
 
52997
                                cat = &thr->catchstack[thr->catchstack_top - 1];
 
52998
                                DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));  /* cleared before entering catch part */
 
52999
 
 
53000
                                if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
 
53001
                                        duk_hobject *prev_env;
 
53002
 
 
53003
                                        /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
 
53004
                                        DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
 
53005
                                        DUK_ASSERT(act->lex_env != NULL);
 
53006
 
 
53007
                                        DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment");
 
53008
 
 
53009
                                        prev_env = act->lex_env;
 
53010
                                        DUK_ASSERT(prev_env != NULL);
 
53011
                                        act->lex_env = prev_env->prototype;
 
53012
                                        DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
 
53013
                                        DUK_HOBJECT_DECREF(thr, prev_env);  /* side effects */
 
53014
                                }
 
53015
 
 
53016
                                if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
 
53017
                                        DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'");
 
53018
                        
 
53019
                                        tv1 = &thr->valstack[cat->idx_base];
 
53020
                                        DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
 
53021
                                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
53022
                                        DUK_TVAL_SET_UNDEFINED_ACTUAL(tv1);
 
53023
                                        DUK_TVAL_DECREF(thr, &tv_tmp);     /* side effects */
 
53024
                                        tv1 = NULL;
 
53025
 
 
53026
                                        tv1 = &thr->valstack[cat->idx_base + 1];
 
53027
                                        DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
 
53028
                                        DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
 
53029
                                        DUK_TVAL_SET_NUMBER(tv1, (double) DUK_LJ_TYPE_NORMAL);
 
53030
                                        DUK_TVAL_DECREF(thr, &tv_tmp);     /* side effects */
 
53031
                                        tv1 = NULL;
 
53032
 
 
53033
                                        DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
 
53034
                                } else {
 
53035
                                        DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)");
 
53036
                                        duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
 
53037
                                        /* no need to unwind callstack */
 
53038
                                }
 
53039
 
 
53040
                                act->pc = cat->pc_base + 1;
 
53041
                                break;
 
53042
                        }
 
53043
 
 
53044
                        case DUK_EXTRAOP_ENDFIN: {
 
53045
                                duk_context *ctx = (duk_context *) thr;
 
53046
                                duk_catcher *cat;
 
53047
                                duk_tval *tv1;
 
53048
                                int cont_type;
 
53049
 
 
53050
                                DUK_ASSERT(thr->catchstack_top >= 1);
 
53051
                                DUK_ASSERT(thr->callstack_top >= 1);
 
53052
                                DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
 
53053
 
 
53054
                                cat = &thr->catchstack[thr->catchstack_top - 1];
 
53055
 
 
53056
                                /* CATCH flag may be enabled or disabled here; it may be enabled if
 
53057
                                 * the statement has a catch block but the try block does not throw
 
53058
                                 * an error.
 
53059
                                 */
 
53060
                                DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat));  /* cleared before entering finally */
 
53061
                                /* FIXME: assert idx_base */
 
53062
 
 
53063
                                DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
 
53064
                                             &thr->valstack[cat->idx_base + 0],
 
53065
                                             &thr->valstack[cat->idx_base + 1]);
 
53066
 
 
53067
                                tv1 = &thr->valstack[cat->idx_base + 1];  /* type */
 
53068
                                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
 
53069
                                cont_type = (int) DUK_TVAL_GET_NUMBER(tv1);
 
53070
 
 
53071
                                if (cont_type == DUK_LJ_TYPE_NORMAL) {
 
53072
                                        DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
 
53073
                                                     "dismantle catcher, resume execution after ENDFIN");
 
53074
                                        duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
 
53075
                                        /* no need to unwind callstack */
 
53076
                                } else {
 
53077
                                        DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%d -> "
 
53078
                                                     "dismantle catcher, re-throw error",
 
53079
                                                     cont_type);
 
53080
 
 
53081
                                        duk_push_tval(ctx, &thr->valstack[cat->idx_base]);
 
53082
 
 
53083
                                        /* FIXME: assert lj type valid */
 
53084
                                        duk_err_setup_heap_ljstate(thr, cont_type);
 
53085
 
 
53086
                                        DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
 
53087
                                        duk_err_longjmp(thr);
 
53088
                                        DUK_UNREACHABLE();
 
53089
                                }
 
53090
 
 
53091
                                /* continue execution after ENDFIN */
 
53092
                                break;
 
53093
                        }
 
53094
 
 
53095
                        case DUK_EXTRAOP_THROW: {
 
53096
                                duk_context *ctx = (duk_context *) thr;
 
53097
                                int b = DUK_DEC_B(ins);
 
53098
 
 
53099
                                /* Note: errors are augmented when they are created, not
 
53100
                                 * when they are thrown.  So, don't augment here, it would
 
53101
                                 * break re-throwing for instance.
 
53102
                                 */
 
53103
 
 
53104
                                duk_dup(ctx, b);
 
53105
                                DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)", duk_get_tval(ctx, -1));
 
53106
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
 
53107
                                duk_err_augment_error_throw(thr);
 
53108
                                DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)", duk_get_tval(ctx, -1));
 
53109
#endif
 
53110
 
 
53111
                                duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
 
53112
 
 
53113
                                DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
 
53114
                                duk_err_longjmp(thr);
 
53115
 
 
53116
                                DUK_UNREACHABLE();
 
53117
                                break;
 
53118
                        }
 
53119
 
 
53120
                        case DUK_EXTRAOP_INVLHS: {
 
53121
                                DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "invalid lvalue");
 
53122
 
 
53123
                                DUK_UNREACHABLE();
 
53124
                                break;
 
53125
                        }
 
53126
 
 
53127
                        case DUK_EXTRAOP_UNM:
 
53128
                        case DUK_EXTRAOP_UNP:
 
53129
                        case DUK_EXTRAOP_INC:
 
53130
                        case DUK_EXTRAOP_DEC: {
 
53131
                                int b = DUK_DEC_B(ins);
 
53132
                                int c = DUK_DEC_C(ins);
 
53133
 
 
53134
                                duk__vm_arith_unary_op(thr, DUK__REGCONSTP(c), b, extraop);
 
53135
                                break;
 
53136
                        }
 
53137
                        default: {
 
53138
                                DUK__INTERNAL_ERROR("invalid extra opcode");
 
53139
                        }
 
53140
 
 
53141
                        }  /* end switch */
 
53142
 
 
53143
                        break;
 
53144
                }
 
53145
 
 
53146
                case DUK_OP_DEBUG: {
 
53147
#ifdef DUK_USE_DEBUG
 
53148
                        switch (DUK_DEC_A(ins)) {
 
53149
 
 
53150
                        case DUK_DEBUGOP_DUMPREG: {
 
53151
                                DUK_DPRINT("DUMPREG: %d -> %!T",
 
53152
                                           DUK_DEC_BC(ins),
 
53153
                                           duk_get_tval((duk_context *) thr, DUK_DEC_BC(ins)));
 
53154
                                break;
 
53155
                        }
 
53156
 
 
53157
                        case DUK_DEBUGOP_DUMPREGS: {
 
53158
                                int i, i_top;
 
53159
                                i_top = duk_get_top((duk_context *) thr);
 
53160
                                DUK_DPRINT("DUMPREGS: %d regs", i_top);
 
53161
                                for (i = 0; i < i_top; i++) {
 
53162
                                        DUK_DPRINT("  r%d -> %!dT", i, duk_get_tval((duk_context *) thr, i));
 
53163
                                }
 
53164
                                break;
 
53165
                        }
 
53166
 
 
53167
                        case DUK_DEBUGOP_DUMPTHREAD: {
 
53168
                                DUK_DEBUG_DUMP_HTHREAD(thr);
 
53169
                                break;
 
53170
                        }
 
53171
 
 
53172
                        case DUK_DEBUGOP_LOGMARK: {
 
53173
                                DUK_DPRINT("LOGMARK: mark %d at pc %d", DUK_DEC_BC(ins), act->pc - 1);  /* -1, autoinc */
 
53174
                                break;
 
53175
                        }
 
53176
 
 
53177
                        default: {
 
53178
                                DUK__INTERNAL_ERROR("invalid debug opcode");
 
53179
                        }
 
53180
 
 
53181
                        }  /* end switch */
 
53182
#endif
 
53183
                        break;
 
53184
                }
 
53185
 
 
53186
                case DUK_OP_INVALID: {
 
53187
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "INVALID opcode (%d)", DUK_DEC_ABC(ins));
 
53188
                        break;
 
53189
                }
 
53190
 
 
53191
                default: {
 
53192
                        /* this should never be possible, because the switch-case is
 
53193
                         * comprehensive
 
53194
                         */
 
53195
                        DUK__INTERNAL_ERROR("invalid opcode");
 
53196
                        break;
 
53197
                }
 
53198
 
 
53199
                }  /* end switch */
 
53200
        }
 
53201
        DUK_UNREACHABLE();
 
53202
 
 
53203
#ifndef DUK_USE_VERBOSE_EXECUTOR_ERRORS
 
53204
 internal_error:
 
53205
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "internal error in bytecode executor");
 
53206
#endif
 
53207
}
 
53208
 
 
53209
#undef DUK__INTERNAL_ERROR
 
53210
 
 
53211
#line 1 "duk_js_ops.c"
 
53212
/*
 
53213
 *  Ecmascript specification algorithm and conversion helpers.
 
53214
 *
 
53215
 *  These helpers encapsulate the primitive Ecmascript operation
 
53216
 *  semantics, and are used by the bytecode executor and the API
 
53217
 *  (among other places).  Note that some primitives are only
 
53218
 *  implemented as part of the API and have no "internal" helper.
 
53219
 *  (This is the case when an internal helper would not really be
 
53220
 *  useful; e.g. the operation is rare, uses value stack heavily,
 
53221
 *  etc.)
 
53222
 *
 
53223
 *  The operation arguments depend on what is required to implement
 
53224
 *  the operation:
 
53225
 *
 
53226
 *    - If an operation is simple and stateless, and has no side
 
53227
 *      effects, it won't take an duk_hthread argument and its
 
53228
 *      arguments may be duk_tval pointers (which are safe as long
 
53229
 *      as no side effects take place).
 
53230
 *
 
53231
 *    - If complex coercions are required (e.g. a "ToNumber" coercion)
 
53232
 *      or errors may be thrown, the operation takes an duk_hthread
 
53233
 *      argument.  This also implies that the operation may have
 
53234
 *      arbitrary side effects, invalidating any duk_tval pointers.
 
53235
 *
 
53236
 *    - For operations with potential side effects, arguments can be
 
53237
 *      taken in several ways:
 
53238
 *
 
53239
 *      a) as duk_tval pointers, which makes sense if the "common case"
 
53240
 *         can be resolved without side effects (e.g. coercion); the
 
53241
 *         arguments are pushed to the valstack for coercion if
 
53242
 *         necessary
 
53243
 *
 
53244
 *      b) as duk_tval values
 
53245
 *
 
53246
 *      c) implicitly on value stack top
 
53247
 *
 
53248
 *      d) as indices to the value stack
 
53249
 *
 
53250
 *  Future work:
 
53251
 *
 
53252
 *     - Argument styles may not be the most sensible in every case now.
 
53253
 *
 
53254
 *     - In-place coercions might be useful for several operations, if
 
53255
 *       in-place coercion is OK for the bytecode executor and the API.
 
53256
 */
 
53257
 
 
53258
/* include removed: duk_internal.h */
 
53259
 
 
53260
/*
 
53261
 *  [[DefaultValue]]  (E5 Section 8.12.8)
 
53262
 *
 
53263
 *  ==> implemented in the API.
 
53264
 */
 
53265
 
 
53266
/*
 
53267
 *  ToPrimitive()  (E5 Section 9.1)
 
53268
 *
 
53269
 *  ==> implemented in the API.
 
53270
 */
 
53271
 
 
53272
/*
 
53273
 *  ToBoolean()  (E5 Section 9.2)
 
53274
 */
 
53275
 
 
53276
int duk_js_toboolean(duk_tval *tv) {
 
53277
        switch (DUK_TVAL_GET_TAG(tv)) {
 
53278
        case DUK_TAG_UNDEFINED:
 
53279
        case DUK_TAG_NULL:
 
53280
                return 0;
 
53281
        case DUK_TAG_BOOLEAN:
 
53282
                return DUK_TVAL_GET_BOOLEAN(tv);
 
53283
        case DUK_TAG_STRING: {
 
53284
                duk_hstring *h = DUK_TVAL_GET_STRING(tv);
 
53285
                DUK_ASSERT(h != NULL);
 
53286
                return (h->blen > 0 ? 1 : 0);
 
53287
        }
 
53288
        case DUK_TAG_OBJECT: {
 
53289
                return 1;
 
53290
        }
 
53291
        case DUK_TAG_BUFFER: {
 
53292
                /* mimic semantics for strings */
 
53293
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
53294
                DUK_ASSERT(h != NULL);
 
53295
                return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
 
53296
        }
 
53297
        case DUK_TAG_POINTER: {
 
53298
                void *p = DUK_TVAL_GET_POINTER(tv);
 
53299
                return (p != NULL ? 1 : 0);
 
53300
        }
 
53301
        default: {
 
53302
                /* number */
 
53303
                int c;
 
53304
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
53305
                c = DUK_FPCLASSIFY(DUK_TVAL_GET_NUMBER(tv));
 
53306
                if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
 
53307
                        return 0;
 
53308
                } else {
 
53309
                        return 1;
 
53310
                }
 
53311
        }
 
53312
        }
 
53313
        DUK_UNREACHABLE();
 
53314
}
 
53315
 
 
53316
/*
 
53317
 *  ToNumber()  (E5 Section 9.3)
 
53318
 *
 
53319
 *  Value to convert must be on stack top, and is popped before exit.
 
53320
 *
 
53321
 *  See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
 
53322
 *       http://www.cs.indiana.edu/~burger/fp/index.html
 
53323
 *
 
53324
 *  Notes on the conversion:
 
53325
 *
 
53326
 *    - There are specific requirements on the accuracy of the conversion
 
53327
 *      through a "Mathematical Value" (MV), so this conversion is not
 
53328
 *      trivial.
 
53329
 *
 
53330
 *    - Quick rejects (e.g. based on first char) are difficult because
 
53331
 *      the grammar allows leading and trailing white space.
 
53332
 *
 
53333
 *    - Quick reject based on string length is difficult even after
 
53334
 *      accounting for white space; there may be arbitrarily many
 
53335
 *      decimal digits.
 
53336
 *
 
53337
 *    - Standard grammar allows decimal values ("123"), hex values
 
53338
 *      ("0x123") and infinities
 
53339
 *
 
53340
 *    - Unlike source code literals, ToNumber() coerces empty strings
 
53341
 *      and strings with only whitespace to zero (not NaN).
 
53342
 */     
 
53343
 
 
53344
/* E5 Section 9.3.1 */
 
53345
static double duk__tonumber_string_raw(duk_hthread *thr) {
 
53346
        duk_context *ctx = (duk_context *) thr;
 
53347
        int s2n_flags;
 
53348
        double d;
 
53349
 
 
53350
        /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
 
53351
         * garbage.
 
53352
         */
 
53353
        s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
 
53354
                    DUK_S2N_FLAG_ALLOW_EXP |
 
53355
                    DUK_S2N_FLAG_ALLOW_PLUS |
 
53356
                    DUK_S2N_FLAG_ALLOW_MINUS |
 
53357
                    DUK_S2N_FLAG_ALLOW_INF |
 
53358
                    DUK_S2N_FLAG_ALLOW_FRAC |
 
53359
                    DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
 
53360
                    DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
 
53361
                    DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
 
53362
                    DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
 
53363
                    DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
 
53364
 
 
53365
        duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
 
53366
        d = duk_get_number(ctx, -1);
 
53367
        duk_pop(ctx);
 
53368
 
 
53369
        return d;
 
53370
}
 
53371
 
 
53372
double duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
 
53373
        duk_context *ctx = (duk_hthread *) thr;
 
53374
 
 
53375
        DUK_ASSERT(thr != NULL);
 
53376
        DUK_ASSERT(tv != NULL);
 
53377
 
 
53378
        switch (DUK_TVAL_GET_TAG(tv)) {
 
53379
        case DUK_TAG_UNDEFINED: {
 
53380
                /* return a specific NaN (although not strictly necessary) */
 
53381
                duk_double_union du;
 
53382
                DUK_DBLUNION_SET_NAN(&du);
 
53383
                DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
 
53384
                return du.d;
 
53385
        }
 
53386
        case DUK_TAG_NULL: {
 
53387
                /* +0.0 */
 
53388
                return 0.0;
 
53389
        }
 
53390
        case DUK_TAG_BOOLEAN: {
 
53391
                if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
 
53392
                        return 1.0;
 
53393
                }
 
53394
                return 0.0;
 
53395
        }
 
53396
        case DUK_TAG_STRING: {
 
53397
                duk_hstring *h = DUK_TVAL_GET_STRING(tv);
 
53398
                duk_push_hstring(ctx, h);
 
53399
                return duk__tonumber_string_raw(thr);
 
53400
        }
 
53401
        case DUK_TAG_OBJECT: {
 
53402
                /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
 
53403
                 * so use [[DefaultValue]] directly.
 
53404
                 */
 
53405
                double d;
 
53406
                duk_push_tval(ctx, tv);
 
53407
                duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER);  /* 'tv' becomes invalid */
 
53408
 
 
53409
                /* recursive call for a primitive value (guaranteed not to cause second
 
53410
                 * recursion).
 
53411
                 */
 
53412
                d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
 
53413
 
 
53414
                duk_pop(ctx);
 
53415
                return d;
 
53416
        }
 
53417
        case DUK_TAG_BUFFER: {
 
53418
                /* Coerce like a string.  This makes sense because addition also treats
 
53419
                 * buffers like strings.
 
53420
                 */
 
53421
                duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
 
53422
                duk_push_hbuffer(ctx, h);
 
53423
                duk_to_string(ctx, -1);  /* XXX: expensive, but numconv now expects to see a string */
 
53424
                return duk__tonumber_string_raw(thr);
 
53425
        }
 
53426
        case DUK_TAG_POINTER: {
 
53427
                /* Coerce like boolean.  This allows code to do something like:
 
53428
                 *
 
53429
                 *    if (ptr) { ... }
 
53430
                 */
 
53431
                void *p = DUK_TVAL_GET_POINTER(tv);
 
53432
                return (p != NULL ? 1.0 : 0.0);
 
53433
        }
 
53434
        default: {
 
53435
                /* number */
 
53436
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
53437
                return DUK_TVAL_GET_NUMBER(tv);
 
53438
        }
 
53439
        }
 
53440
 
 
53441
        DUK_UNREACHABLE();
 
53442
}
 
53443
 
 
53444
/*
 
53445
 *  ToInteger()  (E5 Section 9.4)
 
53446
 */
 
53447
 
 
53448
/* exposed, used by e.g. duk_bi_date.c */
 
53449
double duk_js_tointeger_number(double x) {
 
53450
        int c = DUK_FPCLASSIFY(x);
 
53451
 
 
53452
        if (c == DUK_FP_NAN) {
 
53453
                return 0.0;
 
53454
        } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
 
53455
                /* XXX: FP_ZERO check can be removed, the else clause handles it
 
53456
                 * correctly (preserving sign).
 
53457
                 */
 
53458
                return x;
 
53459
        } else {
 
53460
                int s = DUK_SIGNBIT(x);
 
53461
                x = DUK_FLOOR(DUK_FABS(x));  /* truncate towards zero */
 
53462
                if (s) {
 
53463
                        x = -x;
 
53464
                }
 
53465
                return x;
 
53466
        }
 
53467
}
 
53468
 
 
53469
double duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
 
53470
        double d = duk_js_tonumber(thr, tv);  /* invalidates tv */
 
53471
        return duk_js_tointeger_number(d);
 
53472
}
 
53473
 
 
53474
/*
 
53475
 *  ToInt32(), ToUint32(), ToUint16()  (E5 Sections 9.5, 9.6, 9.7)
 
53476
 */
 
53477
 
 
53478
/* combined algorithm matching E5 Sections 9.5 and 9.6 */       
 
53479
static double duk__toint32_touint32_helper(double x, int is_toint32) {
 
53480
        int c = DUK_FPCLASSIFY(x);
 
53481
        int s;
 
53482
 
 
53483
        if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
 
53484
                return 0.0;
 
53485
        }
 
53486
 
 
53487
 
 
53488
        /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
 
53489
        s = DUK_SIGNBIT(x);
 
53490
        x = DUK_FLOOR(DUK_FABS(x));
 
53491
        if (s) {
 
53492
                x = -x;
 
53493
        }
 
53494
        
 
53495
        /* NOTE: fmod(x) result sign is same as sign of x, which
 
53496
         * differs from what Javascript wants (see Section 9.6).
 
53497
         */
 
53498
 
 
53499
        x = DUK_FMOD(x, DUK_DOUBLE_2TO32);    /* -> x in ]-2**32, 2**32[ */
 
53500
 
 
53501
        if (x < 0.0) {
 
53502
                x += DUK_DOUBLE_2TO32;
 
53503
        }
 
53504
        /* -> x in [0, 2**32[ */
 
53505
 
 
53506
        if (is_toint32) {
 
53507
                if (x >= DUK_DOUBLE_2TO31) {
 
53508
                        /* x in [2**31, 2**32[ */
 
53509
 
 
53510
                        x -= DUK_DOUBLE_2TO32;  /* -> x in [-2**31,2**31[ */
 
53511
                }
 
53512
        }
 
53513
 
 
53514
        return x;
 
53515
}
 
53516
 
 
53517
duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
 
53518
        double d = duk_js_tonumber(thr, tv);  /* invalidates tv */
 
53519
        d = duk__toint32_touint32_helper(d, 1);
 
53520
        DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
 
53521
        DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0);  /* [-0x80000000,0x7fffffff] */
 
53522
        DUK_ASSERT(d == ((double) ((duk_int32_t) d)));  /* whole, won't clip */
 
53523
        return (duk_int32_t) d;
 
53524
}
 
53525
 
 
53526
 
 
53527
duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
 
53528
        double d = duk_js_tonumber(thr, tv);  /* invalidates tv */
 
53529
        d = duk__toint32_touint32_helper(d, 0);
 
53530
        DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
 
53531
        DUK_ASSERT(d >= 0.0 && d <= 4294967295.0);  /* [0x00000000, 0xffffffff] */
 
53532
        DUK_ASSERT(d == ((double) ((duk_uint32_t) d)));  /* whole, won't clip */
 
53533
        return (duk_uint32_t) d;
 
53534
 
 
53535
}
 
53536
 
 
53537
duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
 
53538
        /* should be a safe way to compute this */
 
53539
        return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
 
53540
}
 
53541
 
 
53542
/*
 
53543
 *  ToString()  (E5 Section 9.8)
 
53544
 *
 
53545
 *  ==> implemented in the API.
 
53546
 */
 
53547
 
 
53548
/*
 
53549
 *  ToObject()  (E5 Section 9.9)
 
53550
 *
 
53551
 *  ==> implemented in the API.
 
53552
 */
 
53553
 
 
53554
/*
 
53555
 *  CheckObjectCoercible()  (E5 Section 9.10)
 
53556
 *
 
53557
 *  Note: no API equivalent now.
 
53558
 */
 
53559
 
 
53560
void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
 
53561
        int tag = DUK_TVAL_GET_TAG(tv_x);
 
53562
 
 
53563
        /* Note: this must match ToObject() behavior */
 
53564
 
 
53565
        if (tag == DUK_TAG_UNDEFINED ||
 
53566
            tag == DUK_TAG_NULL ||
 
53567
            tag == DUK_TAG_POINTER ||
 
53568
            tag == DUK_TAG_BUFFER) {
 
53569
                DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not object coercible");
 
53570
        }
 
53571
}
 
53572
 
 
53573
/*
 
53574
 *  IsCallable()  (E5 Section 9.11)
 
53575
 *
 
53576
 *  XXX: API equivalent is a separate implementation now, and this has
 
53577
 *  currently no callers.
 
53578
 */
 
53579
 
 
53580
#if 0  /* unused */
 
53581
int duk_js_iscallable(duk_tval *tv_x) {
 
53582
        duk_hobject *obj;
 
53583
 
 
53584
        if (!DUK_TVAL_IS_OBJECT(tv_x)) {
 
53585
                return 0;
 
53586
        }
 
53587
        obj = DUK_TVAL_GET_OBJECT(tv_x);
 
53588
        DUK_ASSERT(obj != NULL);
 
53589
 
 
53590
        return DUK_HOBJECT_IS_CALLABLE(obj);
 
53591
}
 
53592
#endif
 
53593
 
 
53594
/*
 
53595
 *  Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
 
53596
 *  9.12).  These have much in common so they can share some helpers.
 
53597
 *
 
53598
 *  FIXME notes:
 
53599
 *
 
53600
 *    - Current implementation (and spec definition) has recursion; this should
 
53601
 *      be fixed if possible.
 
53602
 *
 
53603
 *    - String-to-number coercion should be possible without going through the
 
53604
 *      value stack (and be more compact) if a shared helper is invoked.
 
53605
 *
 
53606
 *    - Non-standard coercion rules for internal types?  For instance:
 
53607
 *
 
53608
 *      + Pointer -> convert to number? or string?
 
53609
 *      + Buffer vs. string -> compare contents
 
53610
 *      + Buffer vs. buffer -> compare contents?  (not for strict mode)
 
53611
 *
 
53612
 *    - The beginning of loose and strict equality are identical: if the type
 
53613
 *      tags are the same, comparison logic is the same -> implement a single
 
53614
 *      helper with a strictness flag?
 
53615
 *
 
53616
 *    - SameValue and strict equals are identical except that zero signs are
 
53617
 *      significant for SameValue but not for strict equals, so it can also go
 
53618
 *      into the same helper.
 
53619
 */
 
53620
 
 
53621
/* Note that this is the same operation for strict and loose equality:
 
53622
 *  - E5 Section 11.9.3, step 1.c (loose)
 
53623
 *  - E5 Section 11.9.6, step 4 (strict)
 
53624
 */
 
53625
 
 
53626
static int duk__js_equals_number(double x, double y) {
 
53627
#if defined(DUK_USE_PARANOID_MATH)
 
53628
        /* Straightforward algorithm, makes fewer compiler assumptions. */
 
53629
        int cx = DUK_FPCLASSIFY(x);
 
53630
        int cy = DUK_FPCLASSIFY(y);
 
53631
        if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
 
53632
                return 0;
 
53633
        }
 
53634
        if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
 
53635
                return 1;
 
53636
        }
 
53637
        if (x == y) {
 
53638
                return 1;
 
53639
        }
 
53640
        return 0;
 
53641
#else  /* DUK_USE_PARANOID_MATH */
 
53642
        /* Better equivalent algorithm.  If the compiler is compliant, C and
 
53643
         * Ecmascript semantics are identical for this particular comparison.
 
53644
         * In particular, NaNs must never compare equal and zeroes must compare
 
53645
         * equal regardless of sign.  Could also use a macro, but this inlines
 
53646
         * already nicely (no difference on gcc, for instance).
 
53647
         */
 
53648
        if (x == y) {
 
53649
                /* IEEE requires that NaNs compare false */
 
53650
                DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
 
53651
                DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
 
53652
                return 1;
 
53653
        } else {
 
53654
                /* IEEE requires that zeros compare the same regardless
 
53655
                 * of their signed, so if both x and y are zeroes, they
 
53656
                 * are caught above.
 
53657
                 */
 
53658
                DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
 
53659
                return 0;
 
53660
        }
 
53661
#endif  /* DUK_USE_PARANOID_MATH */
 
53662
}
 
53663
 
 
53664
static int duk__js_samevalue_number(double x, double y) {
 
53665
#if defined(DUK_USE_PARANOID_MATH)
 
53666
        int cx = DUK_FPCLASSIFY(x);
 
53667
        int cy = DUK_FPCLASSIFY(y);
 
53668
 
 
53669
        if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
 
53670
                /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
 
53671
                return 1;
 
53672
        }
 
53673
        if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
 
53674
                /* Note: cannot assume that a non-zero return value of signbit() would
 
53675
                 * always be the same -- hence cannot (portably) use something like:
 
53676
                 *
 
53677
                 *     signbit(x) == signbit(y)
 
53678
                 */
 
53679
                int sx = (DUK_SIGNBIT(x) ? 1 : 0);
 
53680
                int sy = (DUK_SIGNBIT(y) ? 1 : 0);
 
53681
                return (sx == sy);
 
53682
        }
 
53683
 
 
53684
        /* normal comparison; known:
 
53685
         *   - both x and y are not NaNs (but one of them can be)
 
53686
         *   - both x and y are not zero (but one of them can be)
 
53687
         *   - x and y may be denormal or infinite
 
53688
         */
 
53689
 
 
53690
        return (x == y);
 
53691
#else  /* DUK_USE_PARANOID_MATH */
 
53692
        int cx = DUK_FPCLASSIFY(x);
 
53693
        int cy = DUK_FPCLASSIFY(y);
 
53694
 
 
53695
        if (x == y) {
 
53696
                /* IEEE requires that NaNs compare false */
 
53697
                DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
 
53698
                DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
 
53699
 
 
53700
                /* Using classification has smaller footprint than direct comparison. */
 
53701
                if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
 
53702
                        /* Note: cannot assume that a non-zero return value of signbit() would
 
53703
                         * always be the same -- hence cannot (portably) use something like:
 
53704
                         *
 
53705
                         *     signbit(x) == signbit(y)
 
53706
                         */
 
53707
                        int sx = (DUK_SIGNBIT(x) ? 1 : 0);
 
53708
                        int sy = (DUK_SIGNBIT(y) ? 1 : 0);
 
53709
                        return (sx == sy);
 
53710
                }
 
53711
                return 1;
 
53712
        } else {
 
53713
                /* IEEE requires that zeros compare the same regardless
 
53714
                 * of their signed, so if both x and y are zeroes, they
 
53715
                 * are caught above.
 
53716
                 */
 
53717
                DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
 
53718
 
 
53719
                /* Difference to non-strict/strict comparison is that NaNs compare
 
53720
                 * equal and signed zero signs matter.
 
53721
                 */
 
53722
                if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
 
53723
                        /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
 
53724
                        return 1;
 
53725
                }
 
53726
                return 0;
 
53727
        }
 
53728
#endif  /* DUK_USE_PARANOID_MATH */
 
53729
}
 
53730
 
 
53731
int duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
 
53732
        duk_context *ctx = (duk_context *) thr;
 
53733
        duk_tval *tv_tmp;
 
53734
 
 
53735
        /* If flags != 0 (strict or SameValue), thr can be NULL.  For loose
 
53736
         * equals comparison it must be != NULL.
 
53737
         */
 
53738
        DUK_ASSERT(flags != 0 || thr != NULL);
 
53739
 
 
53740
        /*
 
53741
         *  Same type?
 
53742
         *
 
53743
         *  Note: since number values have no explicit tag in the 8-byte
 
53744
         *  representation, need the awkward if + switch.
 
53745
         */
 
53746
 
 
53747
        if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
 
53748
                if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
 
53749
                        /* SameValue */
 
53750
                        return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
 
53751
                                                        DUK_TVAL_GET_NUMBER(tv_y));
 
53752
                } else {
 
53753
                        /* equals and strict equals */
 
53754
                        return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
 
53755
                                                     DUK_TVAL_GET_NUMBER(tv_y));
 
53756
                }
 
53757
        } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
 
53758
                switch (DUK_TVAL_GET_TAG(tv_x)) {
 
53759
                case DUK_TAG_UNDEFINED:
 
53760
                case DUK_TAG_NULL: {
 
53761
                        return 1;
 
53762
                }
 
53763
                case DUK_TAG_BOOLEAN: {
 
53764
                        return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
 
53765
                }
 
53766
                case DUK_TAG_POINTER: {
 
53767
                        return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
 
53768
                }
 
53769
                case DUK_TAG_STRING:
 
53770
                case DUK_TAG_OBJECT: {
 
53771
                        /* heap pointer comparison suffices */
 
53772
                        return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
 
53773
                }
 
53774
                case DUK_TAG_BUFFER: {
 
53775
                        if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
 
53776
                                /* heap pointer comparison suffices */
 
53777
                                return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
 
53778
                        } else {
 
53779
                                /* non-strict equality for buffers compares contents */
 
53780
                                duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
 
53781
                                duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
 
53782
                                size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
 
53783
                                size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
 
53784
                                void *buf_x;
 
53785
                                void *buf_y;
 
53786
                                if (len_x != len_y) {
 
53787
                                        return 0;
 
53788
                                }
 
53789
                                buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(h_x);
 
53790
                                buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(h_y);
 
53791
                                /* if len_x == len_y == 0, buf_x and/or buf_y may
 
53792
                                 * be NULL, but that's OK.
 
53793
                                 */
 
53794
                                DUK_ASSERT(len_x == len_y);
 
53795
                                DUK_ASSERT(len_x == 0 || buf_x != NULL);
 
53796
                                DUK_ASSERT(len_y == 0 || buf_y != NULL);
 
53797
                                return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0;
 
53798
                        }
 
53799
                }
 
53800
                default: {
 
53801
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
 
53802
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
 
53803
                        DUK_UNREACHABLE();
 
53804
                        return 0;
 
53805
                }
 
53806
                }
 
53807
        }
 
53808
 
 
53809
        if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
 
53810
                return 0;
 
53811
        }
 
53812
 
 
53813
        DUK_ASSERT(flags == 0);  /* non-strict equality from here on */
 
53814
 
 
53815
        /*
 
53816
         *  Types are different; various cases for non-strict comparison
 
53817
         *
 
53818
         *  Since comparison is symmetric, we use a "swap trick" to reduce
 
53819
         *  code size.
 
53820
         */
 
53821
 
 
53822
        /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
 
53823
        if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
 
53824
            (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
 
53825
                return 1;
 
53826
        }
 
53827
 
 
53828
        /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
 
53829
        if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
 
53830
                /* the next 'if' is guaranteed to match after swap */
 
53831
                tv_tmp = tv_x;
 
53832
                tv_x = tv_y;
 
53833
                tv_y = tv_tmp;
 
53834
        }
 
53835
        if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
 
53836
                /* FIXME: this is possible without resorting to the value stack */
 
53837
                double d1, d2;
 
53838
                d2 = DUK_TVAL_GET_NUMBER(tv_y);
 
53839
                duk_push_tval(ctx, tv_x);
 
53840
                duk_to_string(ctx, -1);  /* buffer values are coerced first to string here */
 
53841
                duk_to_number(ctx, -1);
 
53842
                d1 = duk_require_number(ctx, -1);
 
53843
                duk_pop(ctx);
 
53844
                return duk__js_equals_number(d1, d2);
 
53845
        }
 
53846
 
 
53847
        /* Buffer/string -> compare contents. */
 
53848
        if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
 
53849
                tv_tmp = tv_x;
 
53850
                tv_x = tv_y;
 
53851
                tv_y = tv_tmp;
 
53852
        }
 
53853
        if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
 
53854
                duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
 
53855
                duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
 
53856
                size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
 
53857
                size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
 
53858
                void *buf_x;
 
53859
                void *buf_y;
 
53860
                if (len_x != len_y) {
 
53861
                        return 0;
 
53862
                }
 
53863
                buf_x = (void *) DUK_HSTRING_GET_DATA(h_x);
 
53864
                buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(h_y);
 
53865
                /* if len_x == len_y == 0, buf_x and/or buf_y may
 
53866
                 * be NULL, but that's OK.
 
53867
                 */
 
53868
                DUK_ASSERT(len_x == len_y);
 
53869
                DUK_ASSERT(len_x == 0 || buf_x != NULL);
 
53870
                DUK_ASSERT(len_y == 0 || buf_y != NULL);
 
53871
                return (DUK_MEMCMP(buf_x, buf_y, len_x) == 0) ? 1 : 0;
 
53872
        }
 
53873
 
 
53874
        /* Boolean/any -> coerce boolean to number and try again.  If boolean is
 
53875
         * compared to a pointer, the final comparison after coercion now always
 
53876
         * yields false (as pointer vs. number compares to false), but this is
 
53877
         * not special cased.
 
53878
         */
 
53879
        if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
 
53880
                tv_tmp = tv_x;
 
53881
                tv_x = tv_y;
 
53882
                tv_y = tv_tmp;
 
53883
        }
 
53884
        if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
 
53885
                /* ToNumber(bool) is +1.0 or 0.0.  Tagged boolean value is always 0 or 1. */
 
53886
                int rc;
 
53887
                DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
 
53888
                duk_push_tval(ctx, tv_x);
 
53889
                duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
 
53890
                rc = duk_js_equals_helper(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0 /*flags:nonstrict*/);
 
53891
                duk_pop_2(ctx);
 
53892
                return rc;
 
53893
        }
 
53894
 
 
53895
        /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
 
53896
        if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
 
53897
            DUK_TVAL_IS_OBJECT(tv_y)) {
 
53898
                tv_tmp = tv_x;
 
53899
                tv_x = tv_y;
 
53900
                tv_y = tv_tmp;
 
53901
        }
 
53902
        if (DUK_TVAL_IS_OBJECT(tv_x) &&
 
53903
            (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
 
53904
                int rc;
 
53905
                duk_push_tval(ctx, tv_x);
 
53906
                duk_push_tval(ctx, tv_y);
 
53907
                duk_to_primitive(ctx, -2, DUK_HINT_NONE);  /* apparently no hint? */
 
53908
                rc = duk_js_equals_helper(thr, duk_get_tval(ctx, -2), duk_get_tval(ctx, -1), 0 /*flags:nonstrict*/);
 
53909
                duk_pop_2(ctx);
 
53910
                return rc;
 
53911
        }
 
53912
 
 
53913
        /* Nothing worked -> not equal. */
 
53914
        return 0;
 
53915
}
 
53916
 
 
53917
/*
 
53918
 *  Comparisons (x >= y, x > y, x <= y, x < y)
 
53919
 *
 
53920
 *  E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
 
53921
 *  flags to get the rest.
 
53922
 */
 
53923
 
 
53924
/* FIXME: this should probably just operate on the stack top, because it
 
53925
 * needs to push stuff on the stack anyway...
 
53926
 */
 
53927
 
 
53928
int duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
 
53929
        /*
 
53930
         *  String comparison (E5 Section 11.8.5, step 4), which
 
53931
         *  needs to compare codepoint by codepoint.
 
53932
         *
 
53933
         *  However, UTF-8 allows us to use strcmp directly: the shared
 
53934
         *  prefix will be encoded identically (UTF-8 has unique encoding)
 
53935
         *  and the first differing character can be compared with a simple
 
53936
         *  unsigned byte comparison (which strcmp does).
 
53937
         *
 
53938
         *  This will not work properly for non-xutf-8 strings, but this
 
53939
         *  is not an issue for compliance.
 
53940
         */
 
53941
 
 
53942
        size_t h1_len, h2_len, prefix_len;
 
53943
        int rc;
 
53944
 
 
53945
        DUK_ASSERT(h1 != NULL);
 
53946
        DUK_ASSERT(h2 != NULL);
 
53947
        h1_len = DUK_HSTRING_GET_BYTELEN(h1);
 
53948
        h2_len = DUK_HSTRING_GET_BYTELEN(h2);
 
53949
        prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
 
53950
 
 
53951
        /* FIXME: this special case can now be removed with DUK_MEMCMP */
 
53952
        /* memcmp() should return zero (equal) for zero length, but avoid
 
53953
         * it because there are some platform specific bugs.  Don't use
 
53954
         * strncmp() because it stops comparing at a NUL.
 
53955
         */
 
53956
 
 
53957
        if (prefix_len == 0) {
 
53958
                rc = 0;
 
53959
        } else {
 
53960
                rc = DUK_MEMCMP((const char *) DUK_HSTRING_GET_DATA(h1),
 
53961
                                (const char *) DUK_HSTRING_GET_DATA(h2),
 
53962
                                prefix_len);
 
53963
        }
 
53964
 
 
53965
        if (rc < 0) {
 
53966
                return -1;
 
53967
        } else if (rc > 0) {
 
53968
                return 1;
 
53969
        }
 
53970
 
 
53971
        /* prefix matches, lengths matter now */
 
53972
        if (h1_len < h2_len) {
 
53973
                /* e.g. "x" < "xx" */
 
53974
                return -1;
 
53975
        } else if (h1_len > h2_len) {
 
53976
                return 1;
 
53977
        }
 
53978
 
 
53979
        return 0;
 
53980
}
 
53981
 
 
53982
int duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
 
53983
        duk_context *ctx = (duk_context *) thr;
 
53984
        double d1, d2;
 
53985
        int c1, c2;
 
53986
        int s1, s2;
 
53987
        int rc;
 
53988
        int retval;
 
53989
 
 
53990
        duk_push_tval(ctx, tv_x);
 
53991
        duk_push_tval(ctx, tv_y);
 
53992
 
 
53993
        if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
 
53994
                duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
 
53995
                duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
 
53996
        } else {
 
53997
                duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
 
53998
                duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
 
53999
        }
 
54000
 
 
54001
        /* Note: reuse variables */
 
54002
        tv_x = duk_get_tval(ctx, -2);
 
54003
        tv_y = duk_get_tval(ctx, -1);
 
54004
 
 
54005
        if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
 
54006
                duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
 
54007
                duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
 
54008
                DUK_ASSERT(h1 != NULL);
 
54009
                DUK_ASSERT(h2 != NULL);
 
54010
 
 
54011
                rc = duk_js_string_compare(h1, h2);
 
54012
                if (rc < 0) {
 
54013
                        goto lt_true;
 
54014
                } else {
 
54015
                        goto lt_false;
 
54016
                }
 
54017
        } else {
 
54018
                /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
 
54019
                 * preserve it just in case.
 
54020
                 */
 
54021
 
 
54022
                if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
 
54023
                        d1 = duk_to_number(ctx, -2);
 
54024
                        d2 = duk_to_number(ctx, -1);
 
54025
                } else {
 
54026
                        d2 = duk_to_number(ctx, -1);
 
54027
                        d1 = duk_to_number(ctx, -2);
 
54028
                }
 
54029
 
 
54030
                c1 = DUK_FPCLASSIFY(d1);
 
54031
                s1 = DUK_SIGNBIT(d1);
 
54032
                c2 = DUK_FPCLASSIFY(d2);
 
54033
                s2 = DUK_SIGNBIT(d2);
 
54034
 
 
54035
                if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
 
54036
                        goto lt_undefined;
 
54037
                }
 
54038
 
 
54039
                if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
 
54040
                        /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
 
54041
                         * steps e, f, and g.
 
54042
                         */
 
54043
                        goto lt_false;
 
54044
                }
 
54045
 
 
54046
                if (d1 == d2) {
 
54047
                        goto lt_false;
 
54048
                }
 
54049
 
 
54050
                if (c1 == DUK_FP_INFINITE && s1 == 0) {
 
54051
                        /* x == +Infinity */
 
54052
                        goto lt_false;
 
54053
                }
 
54054
 
 
54055
                if (c2 == DUK_FP_INFINITE && s2 == 0) {
 
54056
                        /* y == +Infinity */
 
54057
                        goto lt_true;
 
54058
                }
 
54059
 
 
54060
                if (c2 == DUK_FP_INFINITE && s2 != 0) {
 
54061
                        /* y == -Infinity */
 
54062
                        goto lt_false;
 
54063
                }
 
54064
 
 
54065
                if (c1 == DUK_FP_INFINITE && s1 != 0) {
 
54066
                        /* x == -Infinity */
 
54067
                        goto lt_true;
 
54068
                }
 
54069
 
 
54070
                if (d1 < d2) {
 
54071
                        goto lt_true;
 
54072
                }
 
54073
 
 
54074
                goto lt_false;
 
54075
        }
 
54076
 
 
54077
 lt_undefined:
 
54078
        /* Note: undefined from Section 11.8.5 always results in false
 
54079
         * return (see e.g. Section 11.8.3) - hence special treatment here.
 
54080
         */
 
54081
        retval = 0;
 
54082
        goto cleanup;
 
54083
 
 
54084
 lt_true:
 
54085
        if (flags & DUK_COMPARE_FLAG_NEGATE) {
 
54086
                retval = 0;
 
54087
                goto cleanup;
 
54088
        } else {
 
54089
                retval = 1;
 
54090
                goto cleanup;
 
54091
        }
 
54092
        /* never here */
 
54093
 
 
54094
 lt_false:
 
54095
        if (flags & DUK_COMPARE_FLAG_NEGATE) {
 
54096
                retval = 1;
 
54097
                goto cleanup;
 
54098
        } else {
 
54099
                retval = 0;
 
54100
                goto cleanup;
 
54101
        }
 
54102
        /* never here */
 
54103
 
 
54104
 cleanup:
 
54105
        duk_pop_2(ctx);
 
54106
        return retval;
 
54107
}
 
54108
 
 
54109
/*
 
54110
 *  instanceof
 
54111
 */
 
54112
 
 
54113
/*
 
54114
 *  E5 Section 11.8.6 describes the main algorithm, which uses
 
54115
 *  [[HasInstance]].  [[HasInstance]] is defined for only
 
54116
 *  function objects:
 
54117
 *
 
54118
 *    - Normal functions:
 
54119
 *      E5 Section 15.3.5.3
 
54120
 *    - Functions established with Function.prototype.bind():
 
54121
 *      E5 Section 15.3.4.5.3
 
54122
 *
 
54123
 *  For other objects, a TypeError is thrown.
 
54124
 *
 
54125
 *  FIXME: TypeError descriptions are bad (automatic from API).
 
54126
 *
 
54127
 */
 
54128
 
 
54129
/* FIXME: refactoring -> helper to extract duk_hobject * from a tval would
 
54130
 * be useful here; that function should throw TypeErrors if type expectations
 
54131
 * are incorrect.
 
54132
 */
 
54133
 
 
54134
int duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
 
54135
        duk_context *ctx = (duk_context *) thr;
 
54136
        duk_hobject *func;
 
54137
        duk_hobject *val;
 
54138
        duk_hobject *proto;
 
54139
        duk_uint32_t sanity;
 
54140
 
 
54141
        /*
 
54142
         *  Get the values onto the stack first.  It would be possible to cover
 
54143
         *  some normal cases without resorting to the value stack.
 
54144
         */
 
54145
 
 
54146
        duk_push_tval(ctx, tv_x);
 
54147
        duk_push_tval(ctx, tv_y);
 
54148
        func = duk_require_hobject(ctx, -1);
 
54149
 
 
54150
        /*
 
54151
         *  For bound objects, [[HasInstance]] just calls the target function
 
54152
         *  [[HasInstance]].  If that is again a bound object, repeat until
 
54153
         *  we find a non-bound Function object.
 
54154
         */
 
54155
 
 
54156
        /* FIXME: this bound function resolution also happens elsewhere,
 
54157
         * move into a shared helper.
 
54158
         */
 
54159
 
 
54160
        sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
 
54161
        do {
 
54162
                /* check func supports [[HasInstance]] (this is checked for every function
 
54163
                 * in the bound chain, including the final one)
 
54164
                 */
 
54165
 
 
54166
                if (!DUK_HOBJECT_IS_CALLABLE(func)) {
 
54167
                        /*
 
54168
                         *  Note: of native Ecmascript objects, only Function instances
 
54169
                         *  have a [[HasInstance]] internal property.  Custom objects might
 
54170
                         *  also have it, but not in current implementation.
 
54171
                         *
 
54172
                         *  XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
 
54173
                         */
 
54174
                        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid instanceof rval");
 
54175
                }
 
54176
 
 
54177
                if (!DUK_HOBJECT_HAS_BOUND(func)) {
 
54178
                        break;
 
54179
                }
 
54180
 
 
54181
                /* [ ... lval rval ] */
 
54182
 
 
54183
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);         /* -> [ ... lval rval new_rval ] */
 
54184
                duk_replace(ctx, -1);                                        /* -> [ ... lval new_rval ] */
 
54185
                func = duk_require_hobject(ctx, -1);
 
54186
 
 
54187
                /* func support for [[HasInstance]] checked in the beginning of the loop */
 
54188
        } while (--sanity > 0);
 
54189
 
 
54190
        if (sanity == 0) {
 
54191
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "instanceof bound chain sanity exceeded");
 
54192
        }
 
54193
 
 
54194
        /*
 
54195
         *  'func' is now a non-bound object which supports [[HasInstance]]
 
54196
         *  (which here just means DUK_HOBJECT_FLAG_CALLABLE).  Move on
 
54197
         *  to execute E5 Section 15.3.5.3.
 
54198
         */
 
54199
 
 
54200
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
 
54201
        DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
 
54202
 
 
54203
        /* [ ... lval rval(func) ] */
 
54204
 
 
54205
        val = duk_get_hobject(ctx, -2);
 
54206
        if (!val) {
 
54207
                goto pop_and_false;
 
54208
        }
 
54209
 
 
54210
        duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE);  /* -> [ ... lval rval rval.prototype ] */
 
54211
        proto = duk_require_hobject(ctx, -1);
 
54212
        duk_pop(ctx);  /* -> [ ... lval rval ] */
 
54213
 
 
54214
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
54215
        do {
 
54216
                /*
 
54217
                 *  Note: prototype chain is followed BEFORE first comparison.  This
 
54218
                 *  means that the instanceof lval is never itself compared to the
 
54219
                 *  rval.prototype property.  This is apparently intentional, see E5
 
54220
                 *  Section 15.3.5.3, step 4.a.
 
54221
                 *
 
54222
                 *  Also note:
 
54223
                 *
 
54224
                 *      js> (function() {}) instanceof Function
 
54225
                 *      true
 
54226
                 *      js> Function instanceof Function
 
54227
                 *      true
 
54228
                 *
 
54229
                 *  For the latter, h_proto will be Function.prototype, which is the
 
54230
                 *  built-in Function prototype.  Because Function.[[Prototype]] is
 
54231
                 *  also the built-in Function prototype, the result is true.
 
54232
                 */
 
54233
 
 
54234
                val = val->prototype;
 
54235
 
 
54236
                if (!val) {
 
54237
                        goto pop_and_false;
 
54238
                } else if (val == proto) {
 
54239
                        goto pop_and_true;
 
54240
                }
 
54241
 
 
54242
                /* follow prototype chain */
 
54243
        } while (--sanity > 0);
 
54244
 
 
54245
        if (sanity == 0) {
 
54246
                DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "instanceof prototype chain sanity exceeded");
 
54247
        }
 
54248
        DUK_UNREACHABLE();
 
54249
 
 
54250
 pop_and_false:
 
54251
        duk_pop_2(ctx);
 
54252
        return 0;
 
54253
 
 
54254
 pop_and_true:
 
54255
        duk_pop_2(ctx);
 
54256
        return 1;
 
54257
}
 
54258
 
 
54259
/*
 
54260
 *  in
 
54261
 */
 
54262
 
 
54263
/*
 
54264
 *  E5 Sections 11.8.7, 8.12.6.
 
54265
 *
 
54266
 *  Basically just a property existence check using [[HasProperty]].
 
54267
 *
 
54268
 *  FIXME: TypeError descriptions are bad (automatic from API).
 
54269
 */
 
54270
        
 
54271
int duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
 
54272
        duk_context *ctx = (duk_context *) thr;
 
54273
        int retval;
 
54274
 
 
54275
        /*
 
54276
         *  Get the values onto the stack first.  It would be possible to cover
 
54277
         *  some normal cases without resorting to the value stack (e.g. if
 
54278
         *  lval is already a string).
 
54279
         */
 
54280
 
 
54281
        duk_push_tval(ctx, tv_x);
 
54282
        duk_push_tval(ctx, tv_y);
 
54283
        (void) duk_require_hobject(ctx, -1);  /* TypeError if rval not object */
 
54284
        duk_to_string(ctx, -2);               /* coerce lval with ToString() */
 
54285
 
 
54286
        retval = duk_hobject_hasprop(thr, duk_get_tval(ctx, -1), duk_get_tval(ctx, -2));
 
54287
 
 
54288
        duk_pop_2(ctx);
 
54289
        return retval;
 
54290
}
 
54291
 
 
54292
/*
 
54293
 *  typeof
 
54294
 *
 
54295
 *  E5 Section 11.4.3.
 
54296
 *
 
54297
 *  Very straightforward.  The only question is what to return for our
 
54298
 *  non-standard tag / object types.
 
54299
 *
 
54300
 *  There is an unfortunate string constant define naming problem with
 
54301
 *  typeof return values for e.g. "Object" and "object"; careful with
 
54302
 *  the built-in string defines.  The LC_XXX defines are used for the
 
54303
 *  lowercase variants now.
 
54304
 */
 
54305
 
 
54306
duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
 
54307
        int idx = 0;
 
54308
 
 
54309
        switch (DUK_TVAL_GET_TAG(tv_x)) {
 
54310
        case DUK_TAG_UNDEFINED: {
 
54311
                idx = DUK_STRIDX_UNDEFINED;
 
54312
                break;
 
54313
        }
 
54314
        case DUK_TAG_NULL: {
 
54315
                /* Note: not a typo, "object" is returned for a null value */
 
54316
                idx = DUK_STRIDX_LC_OBJECT;
 
54317
                break;
 
54318
        }
 
54319
        case DUK_TAG_BOOLEAN: {
 
54320
                idx = DUK_STRIDX_LC_BOOLEAN;
 
54321
                break;
 
54322
        }
 
54323
        case DUK_TAG_POINTER: {
 
54324
                /* implementation specific */
 
54325
                idx = DUK_STRIDX_LC_POINTER;
 
54326
                break;
 
54327
        }
 
54328
        case DUK_TAG_STRING: {
 
54329
                idx = DUK_STRIDX_LC_STRING;
 
54330
                break;
 
54331
        }
 
54332
        case DUK_TAG_OBJECT: {
 
54333
                duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
 
54334
                DUK_ASSERT(obj != NULL);
 
54335
                if (DUK_HOBJECT_IS_CALLABLE(obj)) {
 
54336
                        idx = DUK_STRIDX_LC_FUNCTION;
 
54337
                } else {
 
54338
                        idx = DUK_STRIDX_LC_OBJECT;
 
54339
                }
 
54340
                break;
 
54341
        }
 
54342
        case DUK_TAG_BUFFER: {
 
54343
                /* implementation specific */
 
54344
                idx = DUK_STRIDX_LC_BUFFER;
 
54345
                break;
 
54346
        }
 
54347
        default: {
 
54348
                /* number */
 
54349
                DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
 
54350
                idx = DUK_STRIDX_LC_NUMBER;
 
54351
                break;
 
54352
        }
 
54353
        }
 
54354
 
 
54355
        DUK_ASSERT(idx >= 0 && idx < DUK_HEAP_NUM_STRINGS);
 
54356
        return thr->strs[idx];
 
54357
}
 
54358
 
 
54359
/*
 
54360
 *  Array index and length
 
54361
 *
 
54362
 *  Array index: E5 Section 15.4
 
54363
 *  Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
 
54364
 *
 
54365
 *  The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
 
54366
 *  call duk_js_to_arrayindex_string_helper().
 
54367
 */
 
54368
 
 
54369
duk_small_int_t duk_js_to_arrayindex_raw_string(duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_idx) {
 
54370
        duk_uint32_t res, new_res;
 
54371
 
 
54372
        if (blen == 0 || blen > 10) {
 
54373
                goto parse_fail;
 
54374
        }
 
54375
        if (str[0] == (duk_uint8_t) '0' && blen > 1) {
 
54376
                goto parse_fail;
 
54377
        }
 
54378
 
 
54379
        /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
 
54380
         * Leading zeroes are not accepted (zero index "0" is an exception
 
54381
         * handled above).
 
54382
         */
 
54383
 
 
54384
        res = 0;
 
54385
        while (blen-- > 0) {
 
54386
                duk_uint8_t c = *str++;
 
54387
                if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
 
54388
                        new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');
 
54389
                        if (new_res < res) {
 
54390
                                /* overflow, more than 32 bits -> not an array index */
 
54391
                                goto parse_fail;
 
54392
                        }
 
54393
                        res = new_res;
 
54394
                } else {
 
54395
                        goto parse_fail;
 
54396
                }
 
54397
        }
 
54398
 
 
54399
        *out_idx = res;
 
54400
        return 1;
 
54401
 
 
54402
 parse_fail:
 
54403
        *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
 
54404
        return 0;
 
54405
}       
 
54406
 
 
54407
/* Called by duk_hstring.h macros */
 
54408
duk_uint32_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
 
54409
        duk_uint32_t res;
 
54410
        duk_small_int_t rc;
 
54411
 
 
54412
        if (!DUK_HSTRING_HAS_ARRIDX(h)) {
 
54413
                return DUK_HSTRING_NO_ARRAY_INDEX;
 
54414
        }
 
54415
 
 
54416
        rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
 
54417
                                             DUK_HSTRING_GET_BYTELEN(h),
 
54418
                                             &res);
 
54419
        DUK_UNREF(rc);
 
54420
        DUK_ASSERT(rc != 0);
 
54421
        return res;
 
54422
}
 
54423
 
 
54424
#line 1 "duk_js_var.c"
 
54425
/*
 
54426
 *  Identifier access and function closure handling.
 
54427
 *
 
54428
 *  Provides the primitives for slow path identifier accesses: GETVAR,
 
54429
 *  PUTVAR, DELVAR, etc.  The fast path, direct register accesses, should
 
54430
 *  be used for most identifier accesses.  Consequently, these slow path
 
54431
 *  primitives should be optimized for maximum compactness.
 
54432
 *
 
54433
 *  Ecmascript environment records (declarative and object) are represented
 
54434
 *  as internal objects with control keys.  Environment records have a
 
54435
 *  parent record ("outer environment reference") which is represented by
 
54436
 *  the implicit prototype for technical reasons (in other words, it is a
 
54437
 *  convenient field).  The prototype chain is not followed in the ordinary
 
54438
 *  sense for variable lookups.
 
54439
 *
 
54440
 *  See identifier-handling.txt for more details on the identifier algorithms
 
54441
 *  and the internal representation.  See function-objects.txt for details on
 
54442
 *  what function templates and instances are expected to look like.
 
54443
 *
 
54444
 *  Care must be taken to avoid duk_tval pointer invalidation caused by
 
54445
 *  e.g. value stack or object resizing.
 
54446
 *
 
54447
 *  FIXME: properties for function instances could be initialized much more
 
54448
 *  efficiently by creating a property allocation for a certain size and
 
54449
 *  filling in keys and values directly (and INCREFing both with "bulk incref"
 
54450
 *  primitives.
 
54451
 *
 
54452
 *  FIXME: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
 
54453
 *  awkward (especially because they follow the prototype chain); rework
 
54454
 *  if "raw" own property helpers are added.
 
54455
 */
 
54456
 
 
54457
/* include removed: duk_internal.h */
 
54458
 
 
54459
/*
 
54460
 *  Local result type for duk__get_identifier_reference() lookup.
 
54461
 */
 
54462
 
 
54463
typedef struct {
 
54464
        duk_hobject *holder;      /* for object-bound identifiers */
 
54465
        duk_tval *value;          /* for register-bound and declarative env identifiers */
 
54466
        duk_int_t attrs;          /* property attributes for identifier (relevant if value != NULL) */
 
54467
        duk_tval *this_binding;
 
54468
        duk_hobject *env;
 
54469
} duk__id_lookup_result;
 
54470
 
 
54471
/*
 
54472
 *  Create a new function object based on a "template function"
 
54473
 *  which contains compiled bytecode, constants, etc, but lacks
 
54474
 *  a lexical environment.
 
54475
 *
 
54476
 *  Ecmascript requires that each created closure is a separate
 
54477
 *  object, with its own set of editable properties.  However,
 
54478
 *  structured property values (such as the formal arguments
 
54479
 *  list and the variable map) are shared.  Also the bytecode,
 
54480
 *  constants, and inner functions are shared.
 
54481
 *
 
54482
 *  See E5 Section 13.2 for detailed requirements on the function
 
54483
 *  objects; there are no similar requirements for function
 
54484
 *  "templates" which are an implementation dependent feature.
 
54485
 *  Also see function-objects.txt for a discussion on the function
 
54486
 *  instance properties provided by this implementation.
 
54487
 *
 
54488
 *  Notes:
 
54489
 *
 
54490
 *   * Order of internal properties should match frequency of
 
54491
 *     use, since the properties will be linearly scanned on
 
54492
 *     lookup (functions usually don't have enough properties
 
54493
 *     to warrant a hash part).
 
54494
 *
 
54495
 *   * The created closure is independent of its template;
 
54496
 *     they do share the same 'data' buffer object, but the
 
54497
 *     template object itself can be freed even if the closure
 
54498
 *     object remains reachable.
 
54499
 */
 
54500
 
 
54501
static void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f) {
 
54502
        duk_tval *tv, *tv_end;
 
54503
        duk_hobject **funcs, **funcs_end;
 
54504
 
 
54505
        DUK_ASSERT(f->data != NULL);  /* compiled functions must be created 'atomically' */
 
54506
        DUK_UNREF(thr);
 
54507
 
 
54508
        tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(f);
 
54509
        tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(f);
 
54510
        while (tv < tv_end) {
 
54511
                DUK_TVAL_INCREF(thr, tv);
 
54512
                tv++;
 
54513
        }
 
54514
 
 
54515
        funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(f);
 
54516
        funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(f);
 
54517
        while (funcs < funcs_end) {
 
54518
                DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
 
54519
                funcs++;
 
54520
        }
 
54521
}
 
54522
 
 
54523
/* Push a new closure on the stack.
 
54524
 *
 
54525
 * Note: if fun_temp has NEWENV, i.e. a new lexical and variable
 
54526
 * declaration is created when the function is called, only
 
54527
 * outer_lex_env matters (outer_var_env is ignored and may or
 
54528
 * may not be same as outer_lex_env).
 
54529
 */
 
54530
 
 
54531
static const duk_uint16_t duk__closure_copy_proplist[] = {
 
54532
        /* order: most frequent to least frequent */
 
54533
        DUK_STRIDX_INT_VARMAP,
 
54534
        DUK_STRIDX_INT_FORMALS,
 
54535
        DUK_STRIDX_NAME,
 
54536
        DUK_STRIDX_INT_PC2LINE,
 
54537
        DUK_STRIDX_FILE_NAME,
 
54538
        DUK_STRIDX_INT_SOURCE
 
54539
};
 
54540
        
 
54541
void duk_js_push_closure(duk_hthread *thr,
 
54542
                         duk_hcompiledfunction *fun_temp,
 
54543
                         duk_hobject *outer_var_env,
 
54544
                         duk_hobject *outer_lex_env) {
 
54545
        duk_context *ctx = (duk_context *) thr;
 
54546
        duk_hcompiledfunction *fun_clos;
 
54547
        duk_small_uint_t i;
 
54548
        duk_uint32_t len_value;
 
54549
 
 
54550
        DUK_ASSERT(fun_temp != NULL);
 
54551
        DUK_ASSERT(fun_temp->data != NULL);
 
54552
        DUK_ASSERT(fun_temp->funcs != NULL);
 
54553
        DUK_ASSERT(fun_temp->bytecode != NULL);
 
54554
        DUK_ASSERT(outer_var_env != NULL);
 
54555
        DUK_ASSERT(outer_lex_env != NULL);
 
54556
 
 
54557
        duk_push_compiledfunction(ctx);
 
54558
        duk_push_hobject(ctx, &fun_temp->obj);  /* -> [ ... closure template ] */
 
54559
 
 
54560
        fun_clos = (duk_hcompiledfunction *) duk_get_hobject(ctx, -2);  /* XXX: duk_get_hcompiledfunction */
 
54561
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun_clos));
 
54562
        DUK_ASSERT(fun_clos != NULL);
 
54563
        DUK_ASSERT(fun_clos->data == NULL);
 
54564
        DUK_ASSERT(fun_clos->funcs == NULL);
 
54565
        DUK_ASSERT(fun_clos->bytecode == NULL);
 
54566
 
 
54567
        fun_clos->data = fun_temp->data;
 
54568
        fun_clos->funcs = fun_temp->funcs;
 
54569
        fun_clos->bytecode = fun_temp->bytecode;
 
54570
 
 
54571
        /* Note: all references inside 'data' need to get their refcounts
 
54572
         * upped too.  This is the case because refcounts are decreased
 
54573
         * through every function referencing 'data' independently.
 
54574
         */
 
54575
 
 
54576
        DUK_HBUFFER_INCREF(thr, fun_clos->data);
 
54577
        duk__inc_data_inner_refcounts(thr, fun_temp);
 
54578
 
 
54579
        fun_clos->nregs = fun_temp->nregs;
 
54580
        fun_clos->nargs = fun_temp->nargs;
 
54581
 
 
54582
        DUK_ASSERT(fun_clos->data != NULL);
 
54583
        DUK_ASSERT(fun_clos->funcs != NULL);
 
54584
        DUK_ASSERT(fun_clos->bytecode != NULL);
 
54585
 
 
54586
        /* XXX: or copy from template? */
 
54587
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
 
54588
 
 
54589
        /*
 
54590
         *  Init/assert flags, copying them where appropriate.
 
54591
         *  Some flags (like NEWENV) are processed separately below.
 
54592
         */
 
54593
 
 
54594
        /* FIXME: copy flags using a mask */
 
54595
 
 
54596
        DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
 
54597
        DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj);  /* Note: not set in template (has no "prototype") */
 
54598
        DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj));
 
54599
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
 
54600
        DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&fun_clos->obj));
 
54601
        DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&fun_clos->obj));
 
54602
        DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
 
54603
        /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
 
54604
        if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
 
54605
                DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
 
54606
        }
 
54607
        /* DUK_HOBJECT_FLAG_NEWENV: handled below */
 
54608
        DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj));
 
54609
        if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
 
54610
                DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
 
54611
        }
 
54612
        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARRAY(&fun_clos->obj));
 
54613
        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_STRINGOBJ(&fun_clos->obj));
 
54614
        DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARGUMENTS(&fun_clos->obj));
 
54615
 
 
54616
        /*
 
54617
         *  Setup environment record properties based on the template
 
54618
         *  and its flags.
 
54619
         *
 
54620
         *  If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
 
54621
         *  records represent identifiers "outside" the function; the
 
54622
         *  "inner" environment records are created on demand.  Otherwise,
 
54623
         *  the environment records are those that will be directly used
 
54624
         *  (e.g. for declarations).
 
54625
         *
 
54626
         *  _lexenv is always set; _varenv defaults to _lexenv if missing,
 
54627
         *  so _varenv is only set if _lexenv != _varenv.
 
54628
         *
 
54629
         *  This is relatively complex, see doc/identifier-handling.txt.
 
54630
         */
 
54631
 
 
54632
        if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
 
54633
                DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
 
54634
 
 
54635
                if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
 
54636
                        duk_hobject *proto;
 
54637
 
 
54638
                        /*
 
54639
                         *  Named function expression, name needs to be bound
 
54640
                         *  in an intermediate environment record.  The "outer"
 
54641
                         *  lexical/variable environment will thus be:
 
54642
                         *
 
54643
                         *  a) { funcname: <func>, _prototype: outer_lex_env }
 
54644
                         *  b) { funcname: <func>, _prototype:  <globalenv> }  (if outer_lex_env missing)
 
54645
                         */
 
54646
 
 
54647
                        DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME));  /* required if NAMEBINDING set */
 
54648
 
 
54649
                        if (outer_lex_env) {
 
54650
                                proto = outer_lex_env;
 
54651
                        } else {
 
54652
                                proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
54653
                        }
 
54654
 
 
54655
                        /* -> [ ... closure template env ] */
 
54656
                        (void) duk_push_object_helper_proto(ctx,
 
54657
                                                            DUK_HOBJECT_FLAG_EXTENSIBLE |
 
54658
                                                            DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
 
54659
                                                            proto);
 
54660
 
 
54661
                        /* It's important that duk_def_prop() is a 'raw define' so that any
 
54662
                         * properties in an ancestor are never an issue (they should never be
 
54663
                         * e.g. non-writable, but just in case).
 
54664
                         */
 
54665
                        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);       /* -> [ ... closure template env funcname ] */
 
54666
                        duk_dup(ctx, -4);                                    /* -> [ ... closure template env funcname closure ] */
 
54667
                        duk_def_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE);      /* -> [ ... closure template env ] */
 
54668
                        /* env[funcname] = closure */
 
54669
 
 
54670
                        /* [ ... closure template env ] */
 
54671
 
 
54672
                        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
 
54673
                        /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
 
54674
                         * will be ignored anyway
 
54675
                         */
 
54676
 
 
54677
                        /* [ ... closure template ] */
 
54678
                } else {
 
54679
                        /*
 
54680
                         *  Other cases (function declaration, anonymous function expression,
 
54681
                         *  strict direct eval code).  The "outer" environment will be whatever
 
54682
                         *  the caller gave us.
 
54683
                         */
 
54684
 
 
54685
                        duk_push_hobject(ctx, outer_lex_env);  /* -> [ ... closure template env ] */
 
54686
                        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
 
54687
                        /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
 
54688
                         * will be ignored anyway
 
54689
                         */
 
54690
 
 
54691
                        /* [ ... closure template ] */
 
54692
                }
 
54693
        } else {
 
54694
                /*
 
54695
                 *  Function gets no new environment when called.  This is the
 
54696
                 *  case for global code, indirect eval code, and non-strict
 
54697
                 *  direct eval code.  There is no direct correspondence to the
 
54698
                 *  E5 specification, as global/eval code is not exposed as a
 
54699
                 *  function.
 
54700
                 */
 
54701
 
 
54702
                DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
 
54703
 
 
54704
                duk_push_hobject(ctx, outer_lex_env);  /* -> [ ... closure template env ] */
 
54705
                duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
 
54706
 
 
54707
                if (outer_var_env != outer_lex_env) {
 
54708
                        duk_push_hobject(ctx, outer_var_env);  /* -> [ ... closure template env ] */
 
54709
                        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_WC);
 
54710
                }
 
54711
        }
 
54712
#ifdef DUK_USE_DDDEBUG
 
54713
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARENV);
 
54714
        duk_get_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV);
 
54715
        DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
54716
        duk_pop_2(ctx);
 
54717
#endif
 
54718
 
 
54719
        /*
 
54720
         *  Copy some internal properties directly
 
54721
         *
 
54722
         *  The properties will be writable and configurable, but not enumerable.
 
54723
         */
 
54724
 
 
54725
        /* [ ... closure template ] */
 
54726
 
 
54727
        DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
54728
 
 
54729
        for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
 
54730
                int stridx = (int) duk__closure_copy_proplist[i];
 
54731
                if (duk_get_prop_stridx(ctx, -1, stridx)) {
 
54732
                        /* [ ... closure template val ] */
 
54733
                        DUK_DDDPRINT("copying property, stridx=%d -> found", stridx);
 
54734
                        duk_def_prop_stridx(ctx, -3, stridx, DUK_PROPDESC_FLAGS_WC);
 
54735
                } else {
 
54736
                        DUK_DDDPRINT("copying property, stridx=%d -> not found", stridx);
 
54737
                        duk_pop(ctx);
 
54738
                }
 
54739
        }
 
54740
 
 
54741
        /*
 
54742
         *  "length" maps to number of formals (E5 Section 13.2) for
 
54743
         *  function declarations/expressions (non-bound functions).
 
54744
         *  Note that 'nargs' is NOT necessarily equal to the number
 
54745
         *  of arguments.
 
54746
         */
 
54747
 
 
54748
        /* [ ... closure template ] */
 
54749
 
 
54750
        len_value = 0;
 
54751
 
 
54752
        /* FIXME: use helper for size optimization */
 
54753
        if (duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS)) {
 
54754
                /* [ ... closure template formals ] */
 
54755
                DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH));
 
54756
                duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
 
54757
                DUK_ASSERT(duk_is_number(ctx, -1));
 
54758
                len_value = duk_to_int(ctx, -1);
 
54759
                duk_pop_2(ctx);
 
54760
        } else {
 
54761
                duk_pop(ctx);  /* FIXME: this is tedious.. another wrapper function? */
 
54762
                /* FIXME: what to do if _formals is not empty but compiler has optimized
 
54763
                 * it away -- read length from an explicit property then?
 
54764
                 */
 
54765
        }
 
54766
 
 
54767
        duk_push_int(ctx, len_value);  /* [ ... closure template len_value ] */
 
54768
        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
 
54769
 
 
54770
        /*
 
54771
         *  "prototype" is, by default, a fresh object with the "constructor"
 
54772
         *  property.
 
54773
         *
 
54774
         *  Note that this creates a circular reference for every function
 
54775
         *  instance (closure) which prevents refcount-based collection of
 
54776
         *  function instances.
 
54777
         *
 
54778
         *  XXX: Try to avoid creating the default prototype object, because
 
54779
         *  many functions are not used as constructors and the default
 
54780
         *  prototype is unnecessary.  Perhaps it could be created on-demand
 
54781
         *  when it is first accessed?
 
54782
         */
 
54783
 
 
54784
        /* [ ... closure template ] */
 
54785
 
 
54786
        duk_push_object(ctx);  /* -> [ ... closure template newobj ] */
 
54787
        duk_dup(ctx, -3);          /* -> [ ... closure template newobj closure ] */
 
54788
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);  /* -> [ ... closure template newobj ] */
 
54789
        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);     /* -> [ ... closure template ] */
 
54790
 
 
54791
        /*
 
54792
         *  "arguments" and "caller" must be mapped to throwers for
 
54793
         *  strict mode and bound functions (E5 Section 15.3.5).
 
54794
         *
 
54795
         *  XXX: This is expensive to have for every strict function instance.
 
54796
         *  Try to implement as virtual properties or on-demand created properties.
 
54797
         */
 
54798
 
 
54799
        /* [ ... closure template ] */
 
54800
 
 
54801
        if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
 
54802
                duk_def_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
 
54803
                duk_def_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
 
54804
        } else {
 
54805
#ifdef DUK_USE_FUNC_NONSTD_CALLER_PROPERTY
 
54806
                DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value");
 
54807
                duk_push_null(ctx);
 
54808
                duk_def_prop_stridx(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
 
54809
#else
 
54810
                DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used");
 
54811
#endif
 
54812
        }
 
54813
 
 
54814
        /*
 
54815
         *  "name" is a non-standard property found in at least V8, Rhino, smjs.
 
54816
         *  For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
 
54817
         *  for V8 it is writable, non-enumerable, non-configurable.  It is also defined
 
54818
         *  for an anonymous function expression in which case the value is an empty string.
 
54819
         *  We could also leave name 'undefined' for anonymous functions but that would
 
54820
         *  differ from behavior of other engines, so use an empty string.
 
54821
         *
 
54822
         *  XXX: make optional?  costs something per function.
 
54823
         */
 
54824
 
 
54825
        /* [ ... closure template ] */
 
54826
 
 
54827
        if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
 
54828
                /* [ ... closure template name ] */
 
54829
                DUK_ASSERT(duk_is_string(ctx, -1));
 
54830
        } else {
 
54831
                /* [ ... closure template undefined ] */
 
54832
                duk_pop(ctx);
 
54833
                duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
 
54834
        }
 
54835
        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);  /* -> [ ... closure template ] */
 
54836
 
 
54837
        /*
 
54838
         *  Compact the closure, in most cases no properties will be added later.
 
54839
         *  Also, without this the closures end up having unused property slots
 
54840
         *  (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
 
54841
         *  A better future solution would be to allocate the closure directly
 
54842
         *  to correct size (and setup the properties directly without going
 
54843
         *  through the API).
 
54844
         */
 
54845
 
 
54846
        duk_compact(ctx, -2);
 
54847
 
 
54848
        /*
 
54849
         *  Some assertions (E5 Section 13.2).
 
54850
         */
 
54851
 
 
54852
        DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
 
54853
        DUK_ASSERT(fun_clos->obj.prototype == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
 
54854
        DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
 
54855
        DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
 
54856
        DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
 
54857
        DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0);  /* non-standard */
 
54858
        DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
 
54859
                   duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
 
54860
        DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
 
54861
                   duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
 
54862
 
 
54863
        /*
 
54864
         *  Finish
 
54865
         */
 
54866
        
 
54867
        /* [ ... closure template ] */
 
54868
 
 
54869
        DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
 
54870
                     duk_get_tval(ctx, -1), duk_get_tval(ctx, -2));
 
54871
 
 
54872
        duk_pop(ctx);
 
54873
 
 
54874
        /* [ ... closure ] */
 
54875
}
 
54876
 
 
54877
/*
 
54878
 *  Delayed activation environment record initialization (for functions
 
54879
 *  with NEWENV).
 
54880
 *
 
54881
 *  The non-delayed initialization is handled by duk_handle_call().
 
54882
 */
 
54883
 
 
54884
/* shared helper */
 
54885
duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
 
54886
                                                      duk_hobject *func,
 
54887
                                                      duk_uint32_t idx_bottom) {
 
54888
        duk_context *ctx = (duk_context *) thr;
 
54889
        duk_hobject *env;
 
54890
        duk_hobject *parent;
 
54891
        duk_tval *tv;
 
54892
 
 
54893
        DUK_ASSERT(thr != NULL);
 
54894
        DUK_ASSERT(func != NULL);
 
54895
 
 
54896
        tv = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
 
54897
        if (tv) {
 
54898
                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
54899
                DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
 
54900
                parent = DUK_TVAL_GET_OBJECT(tv);
 
54901
        } else {
 
54902
                parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
54903
        }
 
54904
 
 
54905
        (void) duk_push_object_helper(ctx,
 
54906
                                      DUK_HOBJECT_FLAG_EXTENSIBLE |
 
54907
                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
 
54908
                                      -1);  /* no prototype, updated below */
 
54909
        env = duk_require_hobject(ctx, -1);
 
54910
        DUK_ASSERT(env != NULL);
 
54911
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent);  /* parent env is the prototype */
 
54912
 
 
54913
        /* open scope information, for compiled functions only */
 
54914
 
 
54915
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
54916
                /* FIXME: duk_push_hthread etc -> macros at least */
 
54917
                duk_push_hobject(ctx, (duk_hobject *) thr);
 
54918
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_THREAD, DUK_PROPDESC_FLAGS_WEC);
 
54919
                duk_push_hobject(ctx, (duk_hobject *) func);
 
54920
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_CALLEE, DUK_PROPDESC_FLAGS_WEC);
 
54921
                duk_push_int(ctx, idx_bottom);  /* FIXME: type */
 
54922
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_REGBASE, DUK_PROPDESC_FLAGS_WEC);
 
54923
        }
 
54924
 
 
54925
        return env;
 
54926
}
 
54927
 
 
54928
void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
 
54929
                                                        duk_activation *act) {
 
54930
        duk_context *ctx = (duk_context *) thr;
 
54931
        duk_hobject *func;
 
54932
        duk_hobject *env;
 
54933
 
 
54934
        func = act->func;
 
54935
        DUK_ASSERT(func != NULL);
 
54936
        DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));  /* bound functions are never in act->func */
 
54937
 
 
54938
        /*
 
54939
         *  Delayed initialization only occurs for 'NEWENV' functions.
 
54940
         */
 
54941
 
 
54942
        DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
 
54943
        DUK_ASSERT(act->lex_env == NULL);
 
54944
        DUK_ASSERT(act->var_env == NULL);
 
54945
 
 
54946
        env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
 
54947
        DUK_ASSERT(env != NULL);
 
54948
 
 
54949
        DUK_DDDPRINT("created delayed fresh env: %!ipO", env);
 
54950
#ifdef DUK_USE_DDDEBUG
 
54951
        {
 
54952
                duk_hobject *p = env;
 
54953
                while (p) {
 
54954
                        DUK_DDDPRINT("  -> %!ipO", p);
 
54955
                        p = p->prototype;
 
54956
                }
 
54957
        }
 
54958
#endif
 
54959
 
 
54960
        act->lex_env = env;
 
54961
        act->var_env = env;
 
54962
        DUK_HOBJECT_INCREF(thr, env);  /* FIXME: incref by count (here 2 times) */
 
54963
        DUK_HOBJECT_INCREF(thr, env);
 
54964
 
 
54965
        duk_pop(ctx);
 
54966
}
 
54967
 
 
54968
/*
 
54969
 *  Closing environment records.
 
54970
 *
 
54971
 *  The environment record MUST be closed with the thread where its activation
 
54972
 *  is.  In other words (if 'env' is open):
 
54973
 *
 
54974
 *    - 'thr' must match _env.thread
 
54975
 *    - 'func' must match _env.callee
 
54976
 *    - 'regbase' must match _env.regbase
 
54977
 *
 
54978
 *  These are not looked up from the env to minimize code size.
 
54979
 *
 
54980
 *  FIXME: should access the own properties directly instead of using the API
 
54981
 */
 
54982
 
 
54983
void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, int regbase) {
 
54984
        duk_context *ctx = (duk_context *) thr;
 
54985
        duk_uint_fast32_t i;
 
54986
 
 
54987
        DUK_ASSERT(thr != NULL);
 
54988
        DUK_ASSERT(env != NULL);
 
54989
        DUK_ASSERT(func != NULL);
 
54990
 
 
54991
        if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
 
54992
                DUK_DDDPRINT("environment record not a declarative record, or already closed: %!iO", env);
 
54993
                return;
 
54994
        }
 
54995
 
 
54996
        DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %d", env, func, regbase);
 
54997
 
 
54998
        duk_push_hobject(ctx, env);
 
54999
 
 
55000
        /* assertions: env must be closed in the same thread as where it runs */
 
55001
#ifdef DUK_USE_ASSERTIONS
 
55002
        {
 
55003
                /* [... env] */
 
55004
 
 
55005
                if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
 
55006
                        DUK_ASSERT(duk_is_object(ctx, -1));
 
55007
                        DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
 
55008
                }
 
55009
                duk_pop(ctx);
 
55010
 
 
55011
                if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD)) {
 
55012
                        DUK_ASSERT(duk_is_object(ctx, -1));
 
55013
                        DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
 
55014
                }
 
55015
                duk_pop(ctx);
 
55016
 
 
55017
                if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
 
55018
                        DUK_ASSERT(duk_is_number(ctx, -1));
 
55019
                        DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
 
55020
                }
 
55021
                duk_pop(ctx);
 
55022
 
 
55023
                /* [... env] */
 
55024
        }
 
55025
#endif
 
55026
 
 
55027
        if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
55028
                duk_hobject *varmap;
 
55029
                duk_hstring *key;
 
55030
                duk_tval *tv;
 
55031
                int regnum;
 
55032
 
 
55033
                /* XXX: additional conditions when to close variables? we don't want to do it
 
55034
                 * unless the environment may have "escaped" (referenced in a function closure).
 
55035
                 * With delayed environments, the existence is probably good enough of a check.
 
55036
                 */
 
55037
 
 
55038
                /* XXX: any way to detect faster whether something needs to be closed?
 
55039
                 * We now look up _callee and then skip the rest.
 
55040
                 */
 
55041
 
 
55042
                /* Note: we rely on the _varmap having a bunch of nice properties, like:
 
55043
                 *  - being compacted and unmodified during this process
 
55044
                 *  - not containing an array part
 
55045
                 *  - having correct value types
 
55046
                 */
 
55047
 
 
55048
                /* [... env] */
 
55049
 
 
55050
                if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
 
55051
                        DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case");
 
55052
                        duk_pop(ctx);
 
55053
                        goto skip_varmap;
 
55054
                }
 
55055
 
 
55056
                /* [... env callee] */
 
55057
 
 
55058
                if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
 
55059
                        DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties");
 
55060
                        duk_pop_2(ctx);
 
55061
                        goto skip_varmap;
 
55062
                }
 
55063
                varmap = duk_require_hobject(ctx, -1);
 
55064
                DUK_ASSERT(varmap != NULL);
 
55065
 
 
55066
                DUK_DDDPRINT("varmap: %!O", varmap);
 
55067
 
 
55068
                /* [... env callee varmap] */
 
55069
 
 
55070
                DUK_DDDPRINT("copying bound register values, %d bound regs", varmap->e_used);
 
55071
 
 
55072
                for (i = 0; i < (duk_uint_fast32_t) varmap->e_used; i++) {
 
55073
                        key = DUK_HOBJECT_E_GET_KEY(varmap, i);
 
55074
                        DUK_ASSERT(key != NULL);   /* assume keys are compacted */
 
55075
 
 
55076
                        DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(varmap, i));  /* assume plain values */
 
55077
 
 
55078
                        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(varmap, i);
 
55079
                        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));  /* assume value is a number */
 
55080
                        regnum = (int) DUK_TVAL_GET_NUMBER(tv);
 
55081
                        DUK_ASSERT(regnum >= 0 && regnum < ((duk_hcompiledfunction *) func)->nregs);  /* regnum is sane */
 
55082
                        DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
 
55083
                        DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
 
55084
 
 
55085
                        /* XXX: slightly awkward */
 
55086
                        duk_push_hstring(ctx, key);
 
55087
                        duk_push_tval(ctx, thr->valstack + regbase + regnum);
 
55088
                        DUK_DDDPRINT("closing identifier '%s' -> reg %d, value %!T",
 
55089
                                     duk_get_string(ctx, -2), regnum, duk_get_tval(ctx, -1));
 
55090
 
 
55091
                        /* [... env callee varmap key val] */
 
55092
 
 
55093
                        /* if property already exists, overwrites silently */
 
55094
                        duk_def_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE);  /* writable but not deletable */
 
55095
                }
 
55096
 
 
55097
                duk_pop_2(ctx);
 
55098
 
 
55099
                /* [... env] */
 
55100
        }
 
55101
 
 
55102
 skip_varmap:
 
55103
 
 
55104
        /* [... env] */
 
55105
 
 
55106
        duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE);
 
55107
        duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD);
 
55108
        duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE);
 
55109
 
 
55110
        duk_pop(ctx);
 
55111
 
 
55112
        DUK_HOBJECT_SET_ENVRECCLOSED(env);
 
55113
 
 
55114
        DUK_DDDPRINT("environment record after being closed: %!O", env);
 
55115
}
 
55116
 
 
55117
/*
 
55118
 *  GETIDREF: a GetIdentifierReference-like helper.
 
55119
 *
 
55120
 *  Provides a parent traversing lookup and a single level lookup
 
55121
 *  (for HasBinding).
 
55122
 *
 
55123
 *  Instead of returning the value, returns a bunch of values allowing
 
55124
 *  the caller to read, write, or delete the binding.  Value pointers
 
55125
 *  are duk_tval pointers which can be mutated directly as long as
 
55126
 *  refcounts are properly updated.  Note that any operation which may
 
55127
 *  reallocate valstacks or compact objects may invalidate the returned
 
55128
 *  duk_tval (but not object) pointers, so caller must be very careful.
 
55129
 *
 
55130
 *  If starting environment record 'env' is given, 'act' is ignored.
 
55131
 *  However, if 'env' is NULL, the caller may identify, in 'act', an
 
55132
 *  activation which hasn't had its declarative environment initialized
 
55133
 *  yet.  The activation registers are then looked up, and its parent
 
55134
 *  traversed normally.
 
55135
 *
 
55136
 *  The 'out' structure values are only valid if the function returns
 
55137
 *  success (non-zero).
 
55138
 */
 
55139
 
 
55140
/* lookup name from an open declarative record's registers */
 
55141
static int duk__getid_open_decl_env_regs(duk_hthread *thr,
 
55142
                                         duk_hstring *name,
 
55143
                                         duk_hobject *env,
 
55144
                                         duk__id_lookup_result *out) {
 
55145
        duk_hthread *env_thr;
 
55146
        duk_hobject *env_func;
 
55147
        duk_int_t env_regbase;
 
55148
        duk_hobject *varmap;
 
55149
        duk_tval *tv;
 
55150
        duk_int_t reg_rel;
 
55151
        duk_int_t idx;
 
55152
 
 
55153
        DUK_ASSERT(thr != NULL);
 
55154
        DUK_ASSERT(name != NULL);
 
55155
        DUK_ASSERT(env != NULL);
 
55156
        DUK_ASSERT(out != NULL);
 
55157
 
 
55158
        DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
 
55159
 
 
55160
        tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
 
55161
        if (!tv) {
 
55162
                /* env is closed, should be missing _callee, _thread, _regbase */
 
55163
                DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
 
55164
                DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
 
55165
                DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
 
55166
                return 0;
 
55167
        }
 
55168
 
 
55169
        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55170
        DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
 
55171
        DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(tv)));
 
55172
        env_func = DUK_TVAL_GET_OBJECT(tv);
 
55173
        DUK_ASSERT(env_func != NULL);
 
55174
 
 
55175
        tv = duk_hobject_find_existing_entry_tval_ptr(env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
 
55176
        if (!tv) {
 
55177
                return 0;
 
55178
        }
 
55179
        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55180
        varmap = DUK_TVAL_GET_OBJECT(tv);
 
55181
        DUK_ASSERT(varmap != NULL);
 
55182
 
 
55183
        tv = duk_hobject_find_existing_entry_tval_ptr(varmap, name);
 
55184
        if (!tv) {
 
55185
                return 0;
 
55186
        }
 
55187
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
55188
        reg_rel = (duk_int_t) DUK_TVAL_GET_NUMBER(tv);
 
55189
        DUK_ASSERT(reg_rel >= 0 && reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
 
55190
 
 
55191
        tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_THREAD(thr));
 
55192
        DUK_ASSERT(tv != NULL);
 
55193
        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55194
        DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
 
55195
        DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
 
55196
        env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
 
55197
        DUK_ASSERT(env_thr != NULL);
 
55198
 
 
55199
        /* Note: env_thr != thr is quite possible and normal, so careful
 
55200
         * with what thread is used for valstack lookup.
 
55201
         */
 
55202
 
 
55203
        tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
 
55204
        DUK_ASSERT(tv != NULL);
 
55205
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
55206
        env_regbase = (duk_int_t) DUK_TVAL_GET_NUMBER(tv);
 
55207
 
 
55208
        idx = env_regbase + reg_rel;
 
55209
        tv = &env_thr->valstack[idx];
 
55210
        DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end);  /* XXX: more accurate? */
 
55211
 
 
55212
        out->value = tv;
 
55213
        out->attrs = DUK_PROPDESC_FLAGS_W;  /* registers are mutable, non-deletable */
 
55214
        out->this_binding = NULL;  /* implicit this value always undefined for
 
55215
                                    * declarative environment records.
 
55216
                                    */
 
55217
        out->env = env;
 
55218
        out->holder = NULL;
 
55219
 
 
55220
        return 1;
 
55221
}
 
55222
 
 
55223
/* lookup name from current activation record's functions' registers */
 
55224
static int duk__getid_activation_regs(duk_hthread *thr,
 
55225
                                      duk_hstring *name,
 
55226
                                      duk_activation *act,
 
55227
                                      duk__id_lookup_result *out) {
 
55228
        duk_tval *tv;
 
55229
        duk_hobject *func;
 
55230
        duk_hobject *varmap;
 
55231
        duk_int_t reg_rel;
 
55232
        duk_int_t idx;
 
55233
 
 
55234
        DUK_ASSERT(thr != NULL);
 
55235
        DUK_ASSERT(name != NULL);
 
55236
        DUK_ASSERT(act != NULL);
 
55237
        DUK_ASSERT(out != NULL);
 
55238
 
 
55239
        func = act->func;
 
55240
        DUK_ASSERT(func != NULL);
 
55241
        DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
 
55242
 
 
55243
        if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
 
55244
                return 0;
 
55245
        }
 
55246
 
 
55247
        tv = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
 
55248
        if (!tv) {
 
55249
                return 0;
 
55250
        }
 
55251
        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55252
        varmap = DUK_TVAL_GET_OBJECT(tv);
 
55253
        DUK_ASSERT(varmap != NULL);
 
55254
 
 
55255
        tv = duk_hobject_find_existing_entry_tval_ptr(varmap, name);
 
55256
        if (!tv) {
 
55257
                return 0;
 
55258
        }
 
55259
        DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
 
55260
        reg_rel = (duk_int_t) DUK_TVAL_GET_NUMBER(tv);
 
55261
        DUK_ASSERT(reg_rel >= 0 && reg_rel < ((duk_hcompiledfunction *) func)->nregs);
 
55262
 
 
55263
        idx = act->idx_bottom + reg_rel;
 
55264
        DUK_ASSERT(idx >= act->idx_bottom);
 
55265
        tv = &thr->valstack[idx];
 
55266
 
 
55267
        out->value = tv;
 
55268
        out->attrs = DUK_PROPDESC_FLAGS_W;  /* registers are mutable, non-deletable */
 
55269
        out->this_binding = NULL;  /* implicit this value always undefined for
 
55270
                                    * declarative environment records.
 
55271
                                    */
 
55272
        out->env = NULL;
 
55273
        out->holder = NULL;
 
55274
 
 
55275
        return 1;
 
55276
}
 
55277
 
 
55278
static int duk__get_identifier_reference(duk_hthread *thr,
 
55279
                                         duk_hobject *env,
 
55280
                                         duk_hstring *name,
 
55281
                                         duk_activation *act,
 
55282
                                         int parents,
 
55283
                                         duk__id_lookup_result *out) {
 
55284
        duk_tval *tv;
 
55285
        duk_uint32_t sanity;
 
55286
 
 
55287
        DUK_ASSERT(thr != NULL);
 
55288
        DUK_ASSERT(env != NULL || act != NULL);
 
55289
        DUK_ASSERT(name != NULL);
 
55290
        DUK_ASSERT(out != NULL);
 
55291
 
 
55292
        DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
 
55293
        DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
 
55294
 
 
55295
        /*
 
55296
         *  Conceptually, we look for the identifier binding by starting from
 
55297
         *  'env' and following to chain of environment records (represented
 
55298
         *  by the prototype chain).
 
55299
         *
 
55300
         *  If 'env' is NULL, the current activation does not yet have an
 
55301
         *  allocated declarative environment record; this should be treated
 
55302
         *  exactly as if the environment record existed but had no bindings
 
55303
         *  other than register bindings.
 
55304
         *
 
55305
         *  Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
 
55306
         *  the environment will always be initialized immediately; hence
 
55307
         *  a NULL 'env' should only happen with the flag set.  This is the
 
55308
         *  case for: (1) function calls, and (2) strict, direct eval calls.
 
55309
         */
 
55310
 
 
55311
        if (env == NULL && act != NULL) {
 
55312
                duk_hobject *func;
 
55313
 
 
55314
                DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
 
55315
                             "delayed env case, look up activation regs first");
 
55316
 
 
55317
                /*
 
55318
                 *  Try registers
 
55319
                 */
 
55320
 
 
55321
                if (duk__getid_activation_regs(thr, name, act, out)) {
 
55322
                        DUK_DDDPRINT("duk__get_identifier_reference successful: "
 
55323
                                     "name=%!O -> value=%!T, attrs=%d, this=%!T, env=%!O, holder=%!O "
 
55324
                                     "(found from register bindings when env=NULL)",
 
55325
                                     (duk_heaphdr *) name, out->value, (int) out->attrs, out->this_binding,
 
55326
                                     out->env, out->holder);
 
55327
                        return 1;
 
55328
                }
 
55329
 
 
55330
                DUK_DDDPRINT("not found in current activation regs");
 
55331
 
 
55332
                /*
 
55333
                 *  Not found in registers, proceed to the parent record.
 
55334
                 *  Here we need to determine what the parent would be,
 
55335
                 *  if 'env' was not NULL (i.e. same logic as when initializing
 
55336
                 *  the record).
 
55337
                 *
 
55338
                 *  Note that environment initialization is only deferred when
 
55339
                 *  DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
 
55340
                 *    - Function code
 
55341
                 *    - Strict eval code
 
55342
                 *
 
55343
                 *  We only need to check _lexenv here; _varenv exists only if it
 
55344
                 *  differs from _lexenv (and thus _lexenv will also be present).
 
55345
                 */
 
55346
 
 
55347
                if (!parents) {
 
55348
                        DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
 
55349
                                     "(not found from register bindings when env=NULL)");
 
55350
                        goto fail_not_found;
 
55351
                }
 
55352
 
 
55353
                func = act->func;
 
55354
                DUK_ASSERT(func != NULL);
 
55355
                DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
 
55356
 
 
55357
                tv = duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
 
55358
                if (tv) {
 
55359
                        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55360
                        env = DUK_TVAL_GET_OBJECT(tv);
 
55361
                } else {
 
55362
                        DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(func, DUK_HTHREAD_STRING_INT_VARENV(thr)) == NULL);
 
55363
                        env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
 
55364
                }
 
55365
 
 
55366
                DUK_DDDPRINT("continue lookup from env: %!iO", env);
 
55367
        }
 
55368
 
 
55369
        /*
 
55370
         *  Prototype walking starting from 'env'.
 
55371
         *
 
55372
         *  ('act' is not needed anywhere here.)
 
55373
         */
 
55374
 
 
55375
        sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
 
55376
        while (env != NULL) {
 
55377
                duk_tval *tv;
 
55378
                int cl;
 
55379
                duk_int_t attrs;
 
55380
 
 
55381
                DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
 
55382
                             (duk_heaphdr *) name,
 
55383
                             (void *) env,
 
55384
                             (duk_heaphdr *) env);
 
55385
 
 
55386
                DUK_ASSERT(env != NULL);
 
55387
                DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
 
55388
                DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
 
55389
 
 
55390
                cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
 
55391
                DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
 
55392
                if (cl == DUK_HOBJECT_CLASS_DECENV) {
 
55393
                        /*
 
55394
                         *  Declarative environment record.
 
55395
                         *
 
55396
                         *  Identifiers can never be stored in ancestors and are
 
55397
                         *  always plain values, so we can use an internal helper
 
55398
                         *  and access the value directly with an duk_tval ptr.
 
55399
                         *
 
55400
                         *  A closed environment is only indicated by it missing
 
55401
                         *  the "book-keeping" properties required for accessing
 
55402
                         *  register-bound variables.
 
55403
                         */
 
55404
 
 
55405
                        if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
 
55406
                                /* already closed */
 
55407
                                goto skip_regs;
 
55408
                        }
 
55409
 
 
55410
                        if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
 
55411
                                DUK_DDDPRINT("duk__get_identifier_reference successful: "
 
55412
                                             "name=%!O -> value=%!T, attrs=%d, this=%!T, env=%!O, holder=%!O "
 
55413
                                             "(declarative environment record, scope open, found in regs)",
 
55414
                                             (duk_heaphdr *) name, out->value, (int) out->attrs, out->this_binding,
 
55415
                                             out->env, out->holder);
 
55416
                                return 1;
 
55417
                        }
 
55418
                 skip_regs:
 
55419
 
 
55420
                        tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(env, name, &attrs);
 
55421
                        if (tv) {
 
55422
                                out->value = tv;
 
55423
                                out->attrs = attrs;
 
55424
                                out->this_binding = NULL;  /* implicit this value always undefined for
 
55425
                                                            * declarative environment records.
 
55426
                                                            */
 
55427
                                out->env = env;
 
55428
                                out->holder = env;
 
55429
 
 
55430
                                DUK_DDDPRINT("duk__get_identifier_reference successful: "
 
55431
                                             "name=%!O -> value=%!T, attrs=%d, this=%!T, env=%!O, holder=%!O "
 
55432
                                             "(declarative environment record, found in properties)",
 
55433
                                             (duk_heaphdr *) name, out->value, (int) out->attrs, out->this_binding,
 
55434
                                             out->env, out->holder);
 
55435
                                return 1;
 
55436
                        }
 
55437
                } else {
 
55438
                        /*
 
55439
                         *  Object environment record.
 
55440
                         *
 
55441
                         *  Binding (target) object is an external, uncontrolled object.
 
55442
                         *  Identifier may be bound in an ancestor property, and may be
 
55443
                         *  an accessor.
 
55444
                         */
 
55445
 
 
55446
                        /* FIXME: we could save space by using _target OR _this.  If _target, assume
 
55447
                         * this binding is undefined.  If _this, assumes this binding is _this, and
 
55448
                         * target is also _this.  One property would then be enough.
 
55449
                         */
 
55450
 
 
55451
                        duk_hobject *target;
 
55452
 
 
55453
                        DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
 
55454
 
 
55455
                        tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_TARGET(thr));
 
55456
                        DUK_ASSERT(tv != NULL);
 
55457
                        DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
55458
                        target = DUK_TVAL_GET_OBJECT(tv);
 
55459
                        DUK_ASSERT(target != NULL);
 
55460
 
 
55461
                        /* Note: we must traverse the prototype chain, so use an actual
 
55462
                         * hasprop call here.  The property may also be an accessor, so
 
55463
                         * we can't get an duk_tval pointer here.
 
55464
                         *
 
55465
                         * out->holder is NOT set to the actual duk_hobject where the
 
55466
                         * property is found, but rather the target object.
 
55467
                         */
 
55468
 
 
55469
                        if (duk_hobject_hasprop_raw(thr, target, name)) {
 
55470
                                out->value = NULL;  /* can't get value, may be accessor */
 
55471
                                out->attrs = 0;     /* irrelevant when out->value == NULL */
 
55472
                                tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_THIS(thr));
 
55473
                                out->this_binding = tv;  /* may be NULL */
 
55474
                                out->env = env;
 
55475
                                out->holder = target;
 
55476
 
 
55477
                                DUK_DDDPRINT("duk__get_identifier_reference successful: "
 
55478
                                             "name=%!O -> value=%!T, attrs=%d, this=%!T, env=%!O, holder=%!O "
 
55479
                                             "(object environment record)",
 
55480
                                             (duk_heaphdr *) name, out->value, (int) out->attrs, out->this_binding,
 
55481
                                             out->env, out->holder);
 
55482
                                return 1;
 
55483
                        }
 
55484
                }
 
55485
 
 
55486
                if (!parents) {
 
55487
                        DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
 
55488
                                     "(not found from first traversed env)");
 
55489
                        goto fail_not_found;
 
55490
                }
 
55491
 
 
55492
                if (sanity-- == 0) {
 
55493
                        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "prototype chain max depth reached (loop?)");
 
55494
                }
 
55495
                env = env->prototype;
 
55496
        };
 
55497
 
 
55498
        /*
 
55499
         *  Not found (even in global object)
 
55500
         */
 
55501
 
 
55502
 fail_not_found:
 
55503
        return 0;
 
55504
}
 
55505
 
 
55506
/*
 
55507
 *  HASVAR: check identifier binding from a given environment record
 
55508
 *  without traversing its parents.
 
55509
 *
 
55510
 *  This primitive is not exposed to user code as such, but is used
 
55511
 *  internally for e.g. declaration binding instantiation.
 
55512
 *
 
55513
 *  See E5 Sections:
 
55514
 *    10.2.1.1.1 HasBinding(N)
 
55515
 *    10.2.1.2.1 HasBinding(N)
 
55516
 *
 
55517
 *  Note: strictness has no bearing on this check.  Hence we don't take
 
55518
 *  a 'strict' parameter.
 
55519
 */
 
55520
 
 
55521
int duk_js_hasvar_envrec(duk_hthread *thr,
 
55522
                         duk_hobject *env,
 
55523
                         duk_hstring *name) {
 
55524
        duk__id_lookup_result ref;
 
55525
        int parents;
 
55526
 
 
55527
        DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
 
55528
                     "(env -> %!dO)",
 
55529
                     (void *) thr, (void *) env, (duk_heaphdr *) name,
 
55530
                     (duk_heaphdr *) env);
 
55531
 
 
55532
        DUK_ASSERT(thr != NULL);
 
55533
        DUK_ASSERT(env != NULL);
 
55534
        DUK_ASSERT(name != NULL);
 
55535
 
 
55536
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
 
55537
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
 
55538
 
 
55539
        DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
 
55540
        DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
 
55541
 
 
55542
        /* lookup results is ignored */
 
55543
        parents = 0;
 
55544
        return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
 
55545
}
 
55546
 
 
55547
/*
 
55548
 *  GETVAR
 
55549
 *
 
55550
 *  See E5 Sections:
 
55551
 *    11.1.2 Identifier Reference
 
55552
 *    10.3.1 Identifier Resolution
 
55553
 *    11.13.1 Simple Assignment  [example of where the Reference is GetValue'd]
 
55554
 *    8.7.1 GetValue (V)
 
55555
 *    8.12.1 [[GetOwnProperty]] (P)
 
55556
 *    8.12.2 [[GetProperty]] (P)
 
55557
 *    8.12.3 [[Get]] (P)
 
55558
 *
 
55559
 *  If 'throw' is true, always leaves two values on top of stack: [val this].
 
55560
 *
 
55561
 *  If 'throw' is false, returns 0 if identifier cannot be resolved, and the
 
55562
 *  stack will be unaffected in this case.  If identifier is resolved, returns
 
55563
 *  1 and leaves [val this] on top of stack.
 
55564
 *
 
55565
 *  Note: the 'strict' flag of a reference returned by GetIdentifierReference
 
55566
 *  is ignored by GetValue.  Hence we don't take a 'strict' parameter.
 
55567
 *
 
55568
 *  The 'throw' flag is needed for implementing 'typeof' for an unreferenced
 
55569
 *  identifier.  An unreference identifier in other contexts generates a
 
55570
 *  ReferenceError.
 
55571
 */
 
55572
 
 
55573
static int duk__getvar_helper(duk_hthread *thr,
 
55574
                              duk_hobject *env,
 
55575
                              duk_activation *act,
 
55576
                              duk_hstring *name,
 
55577
                              int throw_flag) {
 
55578
        duk_context *ctx = (duk_context *) thr;
 
55579
        duk__id_lookup_result ref;
 
55580
        duk_tval tv_tmp_obj;
 
55581
        duk_tval tv_tmp_key;
 
55582
        int parents;
 
55583
 
 
55584
        DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
 
55585
                     "(env -> %!dO)",
 
55586
                     (void *) thr, (void *) env, (void *) act,
 
55587
                     (duk_heaphdr *) name, (duk_heaphdr *) env);
 
55588
 
 
55589
        DUK_ASSERT(thr != NULL);
 
55590
        DUK_ASSERT(name != NULL);
 
55591
        /* env and act may be NULL */
 
55592
 
 
55593
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
 
55594
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
 
55595
 
 
55596
        parents = 1;     /* follow parent chain */
 
55597
        if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
 
55598
                if (ref.value) {
 
55599
                        DUK_ASSERT(ref.this_binding == NULL);  /* always for register bindings */
 
55600
                        duk_push_tval(ctx, ref.value);
 
55601
                        duk_push_undefined(ctx);
 
55602
                } else {
 
55603
                        DUK_ASSERT(ref.holder != NULL);
 
55604
 
 
55605
                        /* Note: getprop may invoke any getter and invalidate any
 
55606
                         * duk_tval pointers, so this must be done first.
 
55607
                         */
 
55608
 
 
55609
                        if (ref.this_binding) {
 
55610
                                duk_push_tval(ctx, ref.this_binding);
 
55611
                        } else {
 
55612
                                duk_push_undefined(ctx);
 
55613
                        }
 
55614
 
 
55615
                        DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
 
55616
                        DUK_TVAL_SET_STRING(&tv_tmp_key, name);
 
55617
                        (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key);  /* [this value] */
 
55618
 
 
55619
                        /* ref.value, ref.this.binding invalidated here by getprop call */
 
55620
 
 
55621
                        duk_insert(ctx, -2);  /* [this value] -> [value this] */
 
55622
                }
 
55623
 
 
55624
                return 1;
 
55625
        } else {
 
55626
                if (throw_flag) {
 
55627
                        DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR,
 
55628
                                  "identifier '%s' undefined",
 
55629
                                  (char *) DUK_HSTRING_GET_DATA(name));
 
55630
                }
 
55631
 
 
55632
                return 0;
 
55633
        }
 
55634
}
 
55635
 
 
55636
int duk_js_getvar_envrec(duk_hthread *thr,
 
55637
                         duk_hobject *env,
 
55638
                         duk_hstring *name,
 
55639
                         int throw_flag) {
 
55640
        return duk__getvar_helper(thr, env, NULL, name, throw_flag);
 
55641
}
 
55642
 
 
55643
int duk_js_getvar_activation(duk_hthread *thr,
 
55644
                             duk_activation *act,
 
55645
                             duk_hstring *name,
 
55646
                             int throw_flag) {
 
55647
        DUK_ASSERT(act != NULL);
 
55648
        return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
 
55649
}
 
55650
 
 
55651
/*
 
55652
 *  PUTVAR
 
55653
 *
 
55654
 *  See E5 Sections:
 
55655
 *    11.1.2 Identifier Reference
 
55656
 *    10.3.1 Identifier Resolution
 
55657
 *    11.13.1 Simple Assignment  [example of where the Reference is PutValue'd]
 
55658
 *    8.7.2 PutValue (V,W)  [see especially step 3.b, undefined -> automatic global in non-strict mode]
 
55659
 *    8.12.4 [[CanPut]] (P)
 
55660
 *    8.12.5 [[Put]] (P)
 
55661
 *
 
55662
 *  Note: may invalidate any valstack (or object) duk_tval pointers because
 
55663
 *  putting a value may reallocate any object or any valstack.  Caller beware.
 
55664
 */
 
55665
 
 
55666
static void duk__putvar_helper(duk_hthread *thr,
 
55667
                               duk_hobject *env,
 
55668
                               duk_activation *act,
 
55669
                               duk_hstring *name,
 
55670
                               duk_tval *val,
 
55671
                               int strict) {
 
55672
        duk__id_lookup_result ref;
 
55673
        duk_tval tv_tmp_obj;
 
55674
        duk_tval tv_tmp_key;
 
55675
        int parents;
 
55676
 
 
55677
        DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%d "
 
55678
                     "(env -> %!dO, val -> %!T)",
 
55679
                     (void *) thr, (void *) env, (void *) act,
 
55680
                     (duk_heaphdr *) name, (void *) val, strict,
 
55681
                     (duk_heaphdr *) env, val);
 
55682
 
 
55683
        DUK_ASSERT(thr != NULL);
 
55684
        DUK_ASSERT(name != NULL);
 
55685
        DUK_ASSERT(val != NULL);
 
55686
        /* env and act may be NULL */
 
55687
 
 
55688
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
 
55689
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
 
55690
        DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
 
55691
 
 
55692
        /*
 
55693
         *  In strict mode E5 protects 'eval' and 'arguments' from being
 
55694
         *  assigned to (or even declared anywhere).  Attempt to do so
 
55695
         *  should result in a compile time SyntaxError.  See the internal
 
55696
         *  design documentation for details.
 
55697
         *
 
55698
         *  Thus, we should never come here, run-time, for strict code,
 
55699
         *  and name 'eval' or 'arguments'.
 
55700
         */
 
55701
 
 
55702
        DUK_ASSERT(!strict ||
 
55703
                   (name != DUK_HTHREAD_STRING_EVAL(thr) &&
 
55704
                    name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
 
55705
 
 
55706
        /*
 
55707
         *  Lookup variable and update in-place if found.
 
55708
         */
 
55709
 
 
55710
        parents = 1;     /* follow parent chain */
 
55711
 
 
55712
        if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
 
55713
                if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
 
55714
                        /* Update duk_tval in-place if pointer provided and the
 
55715
                         * property is writable.  If the property is not writable
 
55716
                         * (immutable binding), use duk_hobject_putprop() which
 
55717
                         * will respect mutability.
 
55718
                         */
 
55719
                        duk_tval tv_tmp;
 
55720
                        duk_tval *tv_val;
 
55721
 
 
55722
                        DUK_ASSERT(ref.this_binding == NULL);  /* always for register bindings */
 
55723
 
 
55724
                        tv_val = ref.value;
 
55725
                        DUK_ASSERT(tv_val != NULL);
 
55726
                        DUK_TVAL_SET_TVAL(&tv_tmp, tv_val);
 
55727
                        DUK_TVAL_SET_TVAL(tv_val, val);
 
55728
                        DUK_TVAL_INCREF(thr, val);
 
55729
                        DUK_TVAL_DECREF(thr, &tv_tmp);  /* must be last */
 
55730
 
 
55731
                        /* ref.value and ref.this_binding invalidated here */
 
55732
                } else {
 
55733
                        DUK_ASSERT(ref.holder != NULL);
 
55734
 
 
55735
                        DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
 
55736
                        DUK_TVAL_SET_STRING(&tv_tmp_key, name);
 
55737
                        (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
 
55738
 
 
55739
                        /* ref.value and ref.this_binding invalidated here */
 
55740
                }
 
55741
 
 
55742
                return;
 
55743
        }
 
55744
        
 
55745
        /*
 
55746
         *  Not found: write to global object (non-strict) or ReferenceError
 
55747
         *  (strict); see E5 Section 8.7.2, step 3.
 
55748
         */
 
55749
 
 
55750
        if (strict) {
 
55751
                DUK_DDDPRINT("identifier binding not found, strict => reference error");
 
55752
                DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
 
55753
        }
 
55754
 
 
55755
        DUK_DDDPRINT("identifier binding not found, not strict => set to global");
 
55756
 
 
55757
        DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
 
55758
        DUK_TVAL_SET_STRING(&tv_tmp_key, name);
 
55759
        (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0);  /* 0 = no throw */
 
55760
 
 
55761
        /* NB: 'val' may be invalidated here because put_value may realloc valstack,
 
55762
         * caller beware.
 
55763
         */
 
55764
}
 
55765
 
 
55766
void duk_js_putvar_envrec(duk_hthread *thr,
 
55767
                          duk_hobject *env,
 
55768
                          duk_hstring *name,
 
55769
                          duk_tval *val,
 
55770
                          int strict) {
 
55771
        duk__putvar_helper(thr, env, NULL, name, val, strict);
 
55772
}
 
55773
 
 
55774
void duk_js_putvar_activation(duk_hthread *thr,
 
55775
                              duk_activation *act,
 
55776
                              duk_hstring *name,
 
55777
                              duk_tval *val,
 
55778
                              int strict) {
 
55779
        DUK_ASSERT(act != NULL);
 
55780
        duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
 
55781
}
 
55782
 
 
55783
/*
 
55784
 *  DELVAR
 
55785
 *
 
55786
 *  See E5 Sections:
 
55787
 *    11.4.1 The delete operator
 
55788
 *    10.2.1.1.5 DeleteBinding (N)  [declarative environment record]
 
55789
 *    10.2.1.2.5 DeleteBinding (N)  [object environment record]
 
55790
 *
 
55791
 *  Variable bindings established inside eval() are deletable (configurable),
 
55792
 *  other bindings are not, including variables declared in global level.
 
55793
 *  Registers are always non-deletable, and the deletion of other bindings
 
55794
 *  is controlled by the configurable flag.
 
55795
 *
 
55796
 *  For strict mode code, the 'delete' operator should fail with a compile
 
55797
 *  time SyntaxError if applied to identifiers.  Hence, no strict mode
 
55798
 *  run-time deletion of identifiers should ever happen.  This function
 
55799
 *  should never be called from strict mode code!
 
55800
 */
 
55801
 
 
55802
static int duk__delvar_helper(duk_hthread *thr,
 
55803
                              duk_hobject *env,
 
55804
                              duk_activation *act,
 
55805
                              duk_hstring *name) {
 
55806
        duk__id_lookup_result ref;
 
55807
        int parents;
 
55808
 
 
55809
        DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
 
55810
                     "(env -> %!dO)",
 
55811
                     (void *) thr, (void *) env, (void *) act,
 
55812
                     (duk_heaphdr *) name, (duk_heaphdr *) env);
 
55813
 
 
55814
        DUK_ASSERT(thr != NULL);
 
55815
        DUK_ASSERT(name != NULL);
 
55816
        /* env and act may be NULL */
 
55817
 
 
55818
        DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
 
55819
 
 
55820
        parents = 1;     /* follow parent chain */
 
55821
 
 
55822
        if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
 
55823
                if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
55824
                        /* Identifier found in registers (always non-deletable)
 
55825
                         * or declarative environment record and non-configurable.
 
55826
                         */
 
55827
                        return 0;
 
55828
                }
 
55829
                DUK_ASSERT(ref.holder != NULL);
 
55830
 
 
55831
                return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
 
55832
        }
 
55833
 
 
55834
        /*
 
55835
         *  Not found (even in global object).
 
55836
         *
 
55837
         *  In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
 
55838
         *  step 3.b.  In strict mode this case is a compile time SyntaxError so
 
55839
         *  we should not come here.
 
55840
         */
 
55841
 
 
55842
        DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
 
55843
                     "(treated as silent success)",
 
55844
                     (duk_heaphdr *) name);
 
55845
        return 1;
 
55846
}
 
55847
 
 
55848
int duk_js_delvar_envrec(duk_hthread *thr,
 
55849
                         duk_hobject *env,
 
55850
                         duk_hstring *name) {
 
55851
        return duk__delvar_helper(thr, env, NULL, name);
 
55852
}
 
55853
        
 
55854
int duk_js_delvar_activation(duk_hthread *thr,
 
55855
                             duk_activation *act,
 
55856
                             duk_hstring *name) {
 
55857
        DUK_ASSERT(act != NULL);
 
55858
        return duk__delvar_helper(thr, act->lex_env, act, name);
 
55859
}
 
55860
 
 
55861
/*
 
55862
 *  DECLVAR
 
55863
 *
 
55864
 *  See E5 Sections:
 
55865
 *    10.4.3 Entering Function Code
 
55866
 *    10.5 Declaration Binding Instantion
 
55867
 *    12.2 Variable Statement
 
55868
 *    11.1.2 Identifier Reference
 
55869
 *    10.3.1 Identifier Resolution
 
55870
 *
 
55871
 *  Variable declaration behavior is mainly discussed in Section 10.5,
 
55872
 *  and is not discussed in the execution semantics (Sections 11-13).
 
55873
 *
 
55874
 *  Conceptually declarations happen when code (global, eval, function)
 
55875
 *  is entered, before any user code is executed.  In practice, register-
 
55876
 *  bound identifiers are 'declared' automatically (by virtue of being
 
55877
 *  allocated to registers with the initial value 'undefined').  Other
 
55878
 *  identifiers are declared in the function prologue with this primitive.
 
55879
 *
 
55880
 *  Since non-register bindings eventually back to an internal object's
 
55881
 *  properties, the 'prop_flags' argument is used to specify binding
 
55882
 *  type:
 
55883
 *
 
55884
 *    - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
 
55885
 *    - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
 
55886
 *    - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
 
55887
 *      doesn't really matter for internal objects
 
55888
 *
 
55889
 *  All bindings are non-deletable mutable bindings except:
 
55890
 *
 
55891
 *    - Declarations in eval code (mutable, deletable)
 
55892
 *    - 'arguments' binding in strict function code (immutable)
 
55893
 *    - Function name binding of a function expression (immutable)
 
55894
 *
 
55895
 *  Declarations may go to declarative environment records (always
 
55896
 *  so for functions), but may also go to object environment records
 
55897
 *  (e.g. global code).  The global object environment has special
 
55898
 *  behavior when re-declaring a function (but not a variable); see
 
55899
 *  E5.1 specification, Section 10.5, step 5.e.
 
55900
 *
 
55901
 *  Declarations always go to the 'top-most' environment record, i.e.
 
55902
 *  we never check the record chain.  It's not an error even if a
 
55903
 *  property (even an immutable or non-deletable one) of the same name
 
55904
 *  already exists.
 
55905
 *
 
55906
 *  If a declared variable already exists, its value needs to be updated
 
55907
 *  (if possible).  Returns 1 if a PUTVAR needs to be done by the caller;
 
55908
 *  otherwise returns 0.
 
55909
 */
 
55910
 
 
55911
static int duk__declvar_helper(duk_hthread *thr,
 
55912
                               duk_hobject *env,
 
55913
                               duk_hstring *name,
 
55914
                               duk_tval *tv_val,
 
55915
                               int prop_flags,
 
55916
                               int is_func_decl) {
 
55917
        duk_context *ctx = (duk_context *) thr;
 
55918
        duk_hobject *holder;
 
55919
        int parents;
 
55920
        duk__id_lookup_result ref;
 
55921
        duk_tval *tv;
 
55922
 
 
55923
        DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08x, is_func_decl=%d "
 
55924
                     "(env -> %!iO)",
 
55925
                     (void *) thr, (void *) env, (duk_heaphdr *) name,
 
55926
                     tv_val, prop_flags, is_func_decl, (duk_heaphdr *) env);
 
55927
 
 
55928
        DUK_ASSERT(thr != NULL);
 
55929
        DUK_ASSERT(env != NULL);
 
55930
        DUK_ASSERT(name != NULL);
 
55931
        DUK_ASSERT(tv_val != NULL);
 
55932
 
 
55933
        /* Note: in strict mode the compiler should reject explicit
 
55934
         * declaration of 'eval' or 'arguments'.  However, internal
 
55935
         * bytecode may declare 'arguments' in the function prologue.
 
55936
         * We don't bother checking (or asserting) for these now.
 
55937
         */
 
55938
 
 
55939
        /* Note: tv_val is a stable tv_val pointer.  The caller makes
 
55940
         * a value copy into its stack frame, so 'tv_val' is not subject
 
55941
         * to side effects here.
 
55942
         */
 
55943
 
 
55944
        /*
 
55945
         *  Check whether already declared.
 
55946
         *
 
55947
         *  We need to check whether the binding exists in the environment
 
55948
         *  without walking its parents.  However, we still need to check
 
55949
         *  register-bound identifiers and the prototype chain of an object
 
55950
         *  environment target object.
 
55951
         */
 
55952
 
 
55953
        parents = 0;  /* just check 'env' */
 
55954
        if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
 
55955
                int e_idx;
 
55956
                int h_idx;
 
55957
                int flags;
 
55958
 
 
55959
                /*
 
55960
                 *  Variable already declared, ignore re-declaration.
 
55961
                 *  The only exception is the updated behavior of E5.1 for
 
55962
                 *  global function declarations, E5.1 Section 10.5, step 5.e.
 
55963
                 *  This behavior does not apply to global variable declarations.
 
55964
                 */
 
55965
 
 
55966
                if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
 
55967
                        DUK_DDDPRINT("re-declare a binding, ignoring");
 
55968
                        return 1;  /* 1 -> needs a PUTVAR */
 
55969
                }
 
55970
 
 
55971
                /*
 
55972
                 *  Special behavior in E5.1.
 
55973
                 *
 
55974
                 *  Note that even though parents == 0, the conflicting property
 
55975
                 *  may be an inherited property (currently our global object's
 
55976
                 *  prototype is Object.prototype).  Step 5.e first operates on
 
55977
                 *  the existing property (which is potentially in an ancestor)
 
55978
                 *  and then defines a new property in the global object (and
 
55979
                 *  never modifies the ancestor).
 
55980
                 *
 
55981
                 *  Also note that this logic would become even more complicated
 
55982
                 *  if the conflicting property might be a virtual one.  Object
 
55983
                 *  prototype has no virtual properties, though.
 
55984
                 *
 
55985
                 *  FIXME: this is now very awkward, rework.
 
55986
                 */
 
55987
 
 
55988
                DUK_DDDPRINT("re-declare a function binding in global object, "
 
55989
                             "updated E5.1 processing");
 
55990
 
 
55991
                DUK_ASSERT(ref.holder != NULL);
 
55992
                holder = ref.holder;
 
55993
 
 
55994
                /* holder will be set to the target object, not the actual object
 
55995
                 * where the property was found (see duk__get_identifier_reference()).
 
55996
                 */
 
55997
                DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
 
55998
                DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_ARRAY(holder));  /* global object doesn't have array part */
 
55999
 
 
56000
                /* FIXME: use a helper for prototype traversal; no loop check here */
 
56001
                /* must be found: was found earlier, and cannot be inherited */
 
56002
                for (;;) {
 
56003
                        DUK_ASSERT(holder != NULL);
 
56004
                        duk_hobject_find_existing_entry(holder, name, &e_idx, &h_idx);
 
56005
                        if (e_idx >= 0) {
 
56006
                                break;
 
56007
                        }
 
56008
                        holder = holder->prototype;
 
56009
                }
 
56010
                DUK_ASSERT(holder != NULL);
 
56011
                DUK_ASSERT(e_idx >= 0);
 
56012
                /* SCANBUILD: scan-build produces a NULL pointer dereference warning
 
56013
                 * below; it never actually triggers because holder is actually never
 
56014
                 * NULL.
 
56015
                 */
 
56016
 
 
56017
                /* ref.holder is global object, holder is the object with the
 
56018
                 * conflicting property.
 
56019
                 */
 
56020
 
 
56021
                flags = DUK_HOBJECT_E_GET_FLAGS(holder, e_idx);
 
56022
                if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
 
56023
                        if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
56024
                                DUK_DDDPRINT("existing property is a non-configurable "
 
56025
                                             "accessor -> reject");
 
56026
                                goto fail_existing_attributes;
 
56027
                        }
 
56028
                        if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
 
56029
                              (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
 
56030
                                DUK_DDDPRINT("existing property is a non-configurable "
 
56031
                                             "plain property which is not writable and "
 
56032
                                             "enumerable -> reject");
 
56033
                                goto fail_existing_attributes;
 
56034
                        }
 
56035
 
 
56036
                        DUK_DDDPRINT("existing property is not configurable but "
 
56037
                                     "is plain, enumerable, and writable -> "
 
56038
                                     "allow redeclaration");
 
56039
                }
 
56040
 
 
56041
                if (holder == ref.holder) {
 
56042
                        /* FIXME: if duk_hobject_define_property_internal() was updated
 
56043
                         * to handle a pre-existing accessor property, this would be
 
56044
                         * a simple call (like for the ancestor case).
 
56045
                         */
 
56046
                        DUK_DDDPRINT("redefine, offending property in global object itself");
 
56047
 
 
56048
                        if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
 
56049
                                duk_hobject *tmp;
 
56050
 
 
56051
                                tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(holder, e_idx);
 
56052
                                DUK_HOBJECT_E_SET_VALUE_GETTER(holder, e_idx, NULL);
 
56053
                                DUK_HOBJECT_DECREF(thr, tmp);
 
56054
                                DUK_UNREF(tmp);
 
56055
                                tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(holder, e_idx);
 
56056
                                DUK_HOBJECT_E_SET_VALUE_SETTER(holder, e_idx, NULL);
 
56057
                                DUK_HOBJECT_DECREF(thr, tmp);
 
56058
                                DUK_UNREF(tmp);
 
56059
                        } else {
 
56060
                                duk_tval tv_tmp;
 
56061
 
 
56062
                                tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(holder, e_idx);
 
56063
                                DUK_TVAL_SET_TVAL(&tv_tmp, tv);
 
56064
                                DUK_TVAL_SET_UNDEFINED_UNUSED(tv);
 
56065
                                DUK_TVAL_DECREF(thr, &tv_tmp);
 
56066
                        }
 
56067
 
 
56068
                        /* Here tv_val would be potentially invalid if we didn't make
 
56069
                         * a value copy at the caller.
 
56070
                         */
 
56071
 
 
56072
                        tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(holder, e_idx);
 
56073
                        DUK_TVAL_SET_TVAL(tv, tv_val);
 
56074
                        DUK_TVAL_INCREF(thr, tv);
 
56075
                        DUK_HOBJECT_E_SET_FLAGS(holder, e_idx, prop_flags);
 
56076
 
 
56077
                        DUK_DDDPRINT("updated global binding, final result: "
 
56078
                                     "value -> %!T, prop_flags=0x%08x",
 
56079
                                     DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(holder, e_idx),
 
56080
                                     prop_flags);
 
56081
                } else {
 
56082
                        DUK_DDDPRINT("redefine, offending property in ancestor");
 
56083
 
 
56084
                        DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
 
56085
                        duk_push_tval(ctx, tv_val);
 
56086
                        duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
 
56087
                }
 
56088
 
 
56089
                return 0;
 
56090
        }
 
56091
 
 
56092
        /*
 
56093
         *  Not found (in registers or record objects).  Declare
 
56094
         *  to current variable environment.
 
56095
         */
 
56096
 
 
56097
        /*
 
56098
         *  Get holder object
 
56099
         */
 
56100
 
 
56101
        if (DUK_HOBJECT_IS_DECENV(env)) {
 
56102
                holder = env;
 
56103
        } else {
 
56104
                DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
 
56105
 
 
56106
                tv = duk_hobject_find_existing_entry_tval_ptr(env, DUK_HTHREAD_STRING_INT_TARGET(thr));
 
56107
                DUK_ASSERT(tv != NULL);
 
56108
                DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
 
56109
                holder = DUK_TVAL_GET_OBJECT(tv);
 
56110
                DUK_ASSERT(holder != NULL);
 
56111
        }
 
56112
 
 
56113
        /*
 
56114
         *  Define new property
 
56115
         *
 
56116
         *  Note: this may fail if the holder is not extensible.
 
56117
         */
 
56118
 
 
56119
        /* FIXME: this is awkward as we use an internal method which doesn't handle
 
56120
         * extensibility etc correctly.  Basically we'd want to do a [[DefineOwnProperty]]
 
56121
         * or Object.defineProperty() here.
 
56122
         */
 
56123
 
 
56124
        if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
 
56125
                goto fail_not_extensible;
 
56126
        }
 
56127
 
 
56128
        duk_push_hobject(ctx, holder);
 
56129
        duk_push_hstring(ctx, name);
 
56130
        duk_push_tval(ctx, tv_val);
 
56131
        duk_def_prop(ctx, -3, prop_flags);  /* [holder name val] -> [holder] */
 
56132
        duk_pop(ctx);
 
56133
 
 
56134
        return 0;
 
56135
 
 
56136
 fail_existing_attributes:
 
56137
 fail_not_extensible:
 
56138
        DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "declaration failed");
 
56139
        return 0;
 
56140
}
 
56141
 
 
56142
int duk_js_declvar_activation(duk_hthread *thr,
 
56143
                              duk_activation *act,
 
56144
                              duk_hstring *name,
 
56145
                              duk_tval *tv_val,
 
56146
                              int prop_flags,
 
56147
                              int is_func_decl) {
 
56148
        duk_hobject *env;
 
56149
        duk_tval tv_val_copy;
 
56150
 
 
56151
        /*
 
56152
         *  Make a value copy of the input tv_val.  This ensures that
 
56153
         *  side effects cannot invalidate the pointer.
 
56154
         */
 
56155
 
 
56156
        DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
 
56157
        tv_val = &tv_val_copy;
 
56158
 
 
56159
        /*
 
56160
         *  Delayed env creation check
 
56161
         */
 
56162
 
 
56163
        if (!act->var_env) {
 
56164
                DUK_ASSERT(act->lex_env == NULL);
 
56165
                duk_js_init_activation_environment_records_delayed(thr, act);
 
56166
        }
 
56167
        DUK_ASSERT(act->lex_env != NULL);
 
56168
        DUK_ASSERT(act->var_env != NULL);
 
56169
 
 
56170
        env = act->var_env;
 
56171
        DUK_ASSERT(env != NULL);
 
56172
        DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
 
56173
 
 
56174
        return duk__declvar_helper(thr, env, name, tv_val, prop_flags, is_func_decl);
 
56175
}
 
56176
 
 
56177
#line 1 "duk_lexer.c"
 
56178
/*
 
56179
 *  Lexer for source files, ToNumber() string conversions, RegExp expressions,
 
56180
 *  and JSON.
 
56181
 *
 
56182
 *  Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer.  The
 
56183
 *  caller can also rewind the token stream into a certain position which is
 
56184
 *  needed by the compiler part for multi-pass scanning.  Tokens are
 
56185
 *  represented as duk_token structures, and contain line number information.
 
56186
 *  Token types are identified with DUK_TOK_* defines.
 
56187
 *
 
56188
 *  Characters are decoded into a fixed size lookup window consisting of
 
56189
 *  decoded Unicode code points, with window positions past the end of the
 
56190
 *  input filled with an invalid codepoint (-1).  The tokenizer can thus
 
56191
 *  perform multiple character lookups efficiently and with few sanity
 
56192
 *  checks (such as access outside the end of the input), which keeps the
 
56193
 *  tokenization code small at the cost of performance.
 
56194
 * 
 
56195
 *  Character data in tokens (such as identifier names and string literals)
 
56196
 *  is encoded into CESU-8 format on-the-fly while parsing the token in
 
56197
 *  question.  The string data is made reachable to garbage collection by
 
56198
 *  placing the token-related values in value stack entries allocated for
 
56199
 *  this purpose by the caller.  The characters exist in Unicode code point
 
56200
 *  form only in the fixed size lookup window, which keeps character data
 
56201
 *  expansion (of especially ASCII data) low.
 
56202
 *
 
56203
 *  Token parsing supports the full range of Unicode characters as described
 
56204
 *  in the E5 specification.  Parsing has been optimized for ASCII characters
 
56205
 *  because ordinary Ecmascript code consists almost entirely of ASCII
 
56206
 *  characters.  Matching of complex Unicode codepoint sets (such as in the
 
56207
 *  IdentifierStart and IdentifierPart productions) is optimized for size,
 
56208
 *  and is done using a linear scan of a bit-packed list of ranges.  This is
 
56209
 *  very slow, but should never be entered unless the source code actually
 
56210
 *  contains Unicode characters.
 
56211
 *
 
56212
 *  Ecmascript tokenization is partially context sensitive.  First,
 
56213
 *  additional future reserved words are recognized in strict mode (see E5
 
56214
 *  Section 7.6.1.2).  Second, a forward slash character ('/') can be
 
56215
 *  recognized either as starting a RegExp literal or as a division operator,
 
56216
 *  depending on context.  The caller must provide necessary context flags
 
56217
 *  when requesting a new token.
 
56218
 *
 
56219
 *  Future work:
 
56220
 *
 
56221
 *    * Make the input window a circular array to avoid copying.  This would
 
56222
 *      not necessarily complicate the tokenizer much, although it would make
 
56223
 *      the window fetches more expensive (one AND).
 
56224
 *
 
56225
 *    * Make line number tracking optional, as it consumes space.  Also, is
 
56226
 *      tracking end line really useful for tokens?
 
56227
 *
 
56228
 *    * Add a feature flag for disabling UTF-8 decoding of input, as most
 
56229
 *      source code is ASCII.  Because of Unicode escapes written in ASCII,
 
56230
 *      this does not allow Unicode support to be removed from e.g.
 
56231
 *      duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
 
56232
 *      encoding of e.g. string literals.
 
56233
 *
 
56234
 *    * Add a feature flag for disabling Unicode compliance of e.g. identifier
 
56235
 *      names.  This allows for a build more than a kilobyte smaller, because
 
56236
 *      Unicode ranges needed by duk_unicode_is_identifier_start() and
 
56237
 *      duk_unicode_is_identifier_part() can be dropped.  String literals
 
56238
 *      should still be allowed to contain escaped Unicode, so this still does
 
56239
 *      not allow removal of CESU-8 encoding of e.g. string literals.
 
56240
 *
 
56241
 *    * Character lookup tables for codepoints above BMP could be stripped.
 
56242
 *
 
56243
 *    * Strictly speaking, E5 specification requires that source code consists
 
56244
 *      of 16-bit code units, and if not, must be conceptually converted to
 
56245
 *      that format first.  The current lexer processes Unicode code points
 
56246
 *      and allows characters outside the BMP.  These should be converted to
 
56247
 *      surrogate pairs while reading the source characters into the window,
 
56248
 *      not after tokens have been formed (as is done now).  However, the fix
 
56249
 *      is not trivial because two characters are decoded from one codepoint.
 
56250
 *
 
56251
 *    * Optimize for speed as well as size.  Large if-else ladders are slow.
 
56252
 */
 
56253
 
 
56254
/* include removed: duk_internal.h */
 
56255
 
 
56256
/*
 
56257
 *  Various defines and file specific helper macros
 
56258
 */
 
56259
 
 
56260
#define DUK__MAX_RE_DECESC_DIGITS     9
 
56261
#define DUK__MAX_RE_QUANT_DIGITS      9   /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
 
56262
 
 
56263
#define DUK__LOOKUP(lex_ctx,index)    ((lex_ctx)->window[(index)])
 
56264
#define DUK__ADVANCE(lex_ctx,count)   duk__advance_chars((lex_ctx), (count))
 
56265
#define DUK__INITBUFFER(lex_ctx)      duk__initbuffer((lex_ctx))
 
56266
#define DUK__APPENDBUFFER(lex_ctx,x)  duk__appendbuffer((lex_ctx), (int) (x))
 
56267
 
 
56268
/* whether to use macros or helper function depends on call count */
 
56269
#define DUK__ISDIGIT(x)          ((x) >= '0' && (x) <= '9')
 
56270
#define DUK__ISHEXDIGIT(x)       duk__is_hex_digit((x))
 
56271
#define DUK__ISOCTDIGIT(x)       ((x) >= '0' && (x) <= '7')
 
56272
#define DUK__ISDIGIT03(x)        ((x) >= '0' && (x) <= '3')
 
56273
#define DUK__ISDIGIT47(x)        ((x) >= '4' && (x) <= '7')
 
56274
 
 
56275
/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
 
56276
#define DUK__L0()  DUK__LOOKUP(lex_ctx, 0)
 
56277
#define DUK__L1()  DUK__LOOKUP(lex_ctx, 1)
 
56278
#define DUK__L2()  DUK__LOOKUP(lex_ctx, 2)
 
56279
#define DUK__L3()  DUK__LOOKUP(lex_ctx, 3)
 
56280
#define DUK__L4()  DUK__LOOKUP(lex_ctx, 4)
 
56281
#define DUK__L5()  DUK__LOOKUP(lex_ctx, 5)
 
56282
 
 
56283
/* packed advance/token number macro used by multiple functions */
 
56284
#define DUK__ADVTOK(adv,tok)  (((adv) << 8) + (tok))
 
56285
 
 
56286
/*
 
56287
 *  Read a character from the window leading edge and update the line counter.
 
56288
 *
 
56289
 *  Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
 
56290
 *  U+10FFFF, causing an error if the input is unparseable.  Leniency means:
 
56291
 *
 
56292
 *    * Unicode code point validation is intentionally not performed,
 
56293
 *      except to check that the codepoint does not exceed 0x10ffff.
 
56294
 *
 
56295
 *    * In particular, surrogate pairs are allowed and not combined, which
 
56296
 *      allows source files to represent all SourceCharacters with CESU-8.
 
56297
 *      Broken surrogate pairs are allowed, as Ecmascript does not mandate
 
56298
 *      their validation.
 
56299
 *
 
56300
 *    * Allow non-shortest UTF-8 encodings.
 
56301
 *
 
56302
 *  Leniency here causes few security concerns because all character data is
 
56303
 *  decoded into Unicode codepoints before lexer processing, and is then
 
56304
 *  re-encoded into CESU-8.  The source can be parsed as strict UTF-8 with
 
56305
 *  a compiler option.  However, Ecmascript source characters include -all-
 
56306
 *  16-bit unsigned integer codepoints, so leniency seems to be appropriate.
 
56307
 *
 
56308
 *  Note that codepoints above the BMP are not strictly SourceCharacters,
 
56309
 *  but the lexer still accepts them as such.  Before ending up in a string
 
56310
 *  or an identifier name, codepoints above BMP are converted into surrogate
 
56311
 *  pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
 
56312
 *  expected by Ecmascript.
 
56313
 *
 
56314
 *  An alternative approach to dealing with invalid or partial sequences
 
56315
 *  would be to skip them and replace them with e.g. the Unicode replacement
 
56316
 *  character U+FFFD.  This has limited utility because a replacement character
 
56317
 *  will most likely cause a parse error, unless it occurs inside a string.
 
56318
 *  Further, Ecmascript source is typically pure ASCII.
 
56319
 *
 
56320
 *  See:
 
56321
 *
 
56322
 *     http://en.wikipedia.org/wiki/UTF-8
 
56323
 *     http://en.wikipedia.org/wiki/CESU-8
 
56324
 *     http://tools.ietf.org/html/rfc3629
 
56325
 *     http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
 
56326
 *
 
56327
 *  Future work:
 
56328
 *
 
56329
 *    * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
 
56330
 *      in strict UTF-8 mode.
 
56331
 * 
 
56332
 *    * Size optimize.  An attempt to use a 16-byte lookup table for the first
 
56333
 *      byte resulted in a code increase though.
 
56334
 *
 
56335
 *    * Is checking against maximum 0x10ffff really useful?  4-byte encoding
 
56336
 *      imposes a certain limit anyway.
 
56337
 */
 
56338
 
 
56339
static int duk__read_char(duk_lexer_ctx *lex_ctx) {
 
56340
        /* attempting to reduce size of 'len' and/or 'i' resulted in larger code */
 
56341
        int x;
 
56342
        int len;
 
56343
        int i;
 
56344
        duk_uint8_t *p;
 
56345
#ifdef DUK_USE_STRICT_UTF8_SOURCE
 
56346
        int mincp;
 
56347
#endif
 
56348
 
 
56349
        if (lex_ctx->input_offset >= lex_ctx->input_length) {
 
56350
                return -1;
 
56351
        }
 
56352
 
 
56353
        p = &lex_ctx->input[lex_ctx->input_offset];
 
56354
        x = (int) *p++;
 
56355
 
 
56356
        if (x < 0x80) {
 
56357
                /* 0xxx xxxx -> fast path */
 
56358
                len = 1;
 
56359
                goto fastpath;
 
56360
        } else if (x < 0xc0) {
 
56361
                /* 10xx xxxx -> invalid */
 
56362
                goto error;
 
56363
        } else if (x < 0xe0) {
 
56364
                /* 110x xxxx   10xx xxxx  */
 
56365
                len = 2;
 
56366
#ifdef DUK_USE_STRICT_UTF8_SOURCE
 
56367
                mincp = 0x80;
 
56368
#endif
 
56369
                x = x & 0x1f;
 
56370
        } else if (x < 0xf0) {
 
56371
                /* 1110 xxxx   10xx xxxx   10xx xxxx */
 
56372
                len = 3;
 
56373
#ifdef DUK_USE_STRICT_UTF8_SOURCE
 
56374
                mincp = 0x800;
 
56375
#endif
 
56376
                x = x & 0x0f;
 
56377
        } else if (x < 0xf8) {
 
56378
                /* 1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx */
 
56379
                len = 4;
 
56380
#ifdef DUK_USE_STRICT_UTF8_SOURCE
 
56381
                mincp = 0x10000;
 
56382
#endif
 
56383
                x = x & 0x07;
 
56384
        } else {
 
56385
                /* no point in supporting encodings of 5 or more bytes */
 
56386
                goto error;
 
56387
        }
 
56388
 
 
56389
        if (len > lex_ctx->input_length - lex_ctx->input_offset) {
 
56390
                goto error;
 
56391
        }
 
56392
 
 
56393
        for (i = 1; i < len; i++) {
 
56394
                int y = *p++;
 
56395
                if ((y & 0xc0) != 0x80) {
 
56396
                        /* check that byte has the form 10xx xxxx */
 
56397
                        goto error;
 
56398
                }
 
56399
                x = x << 6;
 
56400
                x += y & 0x3f;
 
56401
        }
 
56402
 
 
56403
        /* check final character validity */
 
56404
 
 
56405
        if (x > 0x10ffff) {
 
56406
                goto error;
 
56407
        }
 
56408
#ifdef DUK_USE_STRICT_UTF8_SOURCE
 
56409
        if (x < mincp || (x >= 0xd800 && x <= 0xdfff) || x == 0xfffe) {
 
56410
                goto error;
 
56411
        }
 
56412
#endif
 
56413
 
 
56414
        /* fall through */
 
56415
 
 
56416
 fastpath:
 
56417
        /* input offset tracking */
 
56418
        lex_ctx->input_offset += len;
 
56419
 
 
56420
        /* line tracking */
 
56421
        if ((x == 0x000a) ||
 
56422
            ((x == 0x000d) && (lex_ctx->input_offset >= lex_ctx->input_length ||
 
56423
                               lex_ctx->input[lex_ctx->input_offset] != 0x000a)) ||
 
56424
            (x == 0x2028) ||
 
56425
            (x == 0x2029)) {
 
56426
                /* lookup for 0x000a above assumes shortest encoding now */
 
56427
 
 
56428
                /* E5 Section 7.3, treat the following as newlines:
 
56429
                 *   LF
 
56430
                 *   CR [not followed by LF]
 
56431
                 *   LS
 
56432
                 *   PS
 
56433
                 *
 
56434
                 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
 
56435
                 * the line number.
 
56436
                 */
 
56437
                lex_ctx->input_line++;
 
56438
        }
 
56439
 
 
56440
        return x;
 
56441
 
 
56442
 error:
 
56443
        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "invalid char encoding in source");
 
56444
        return 0;
 
56445
}
 
56446
 
 
56447
/*
 
56448
 *  Advance lookup window by N characters.  Also used to fill the window
 
56449
 *  after position is changed (call with count == DUK_LEXER_WINDOW_SIZE).
 
56450
 *
 
56451
 *  Future work:
 
56452
 *
 
56453
 *    * A lot of copying now, perhaps change to circular array or at
 
56454
 *      least use memcpy().  For memcpy(), putting all elements of the
 
56455
 *      window (code point, offset, line) into a struct would allow one
 
56456
 *      memcpy() to slide the window, instead of three separate copys.
 
56457
 */
 
56458
 
 
56459
static void duk__advance_chars(duk_lexer_ctx *lex_ctx, int count) {
 
56460
        int i;
 
56461
 
 
56462
        DUK_ASSERT(count >= 0 && count <= DUK_LEXER_WINDOW_SIZE);
 
56463
 
 
56464
        if (count == 0) {
 
56465
                /* allowing zero count makes some special caller flows easier */
 
56466
                return;
 
56467
        }
 
56468
 
 
56469
        for (i = 0; i < DUK_LEXER_WINDOW_SIZE - count; i++) {
 
56470
                lex_ctx->offsets[i] = lex_ctx->offsets[i + count];
 
56471
                lex_ctx->lines[i] = lex_ctx->lines[i + count];
 
56472
                lex_ctx->window[i] = lex_ctx->window[i + count];
 
56473
        }
 
56474
 
 
56475
        for (; i < DUK_LEXER_WINDOW_SIZE; i++) {
 
56476
                lex_ctx->offsets[i] = lex_ctx->input_offset;
 
56477
                lex_ctx->lines[i] = lex_ctx->input_line;
 
56478
                lex_ctx->window[i] = duk__read_char(lex_ctx);
 
56479
        }
 
56480
}
 
56481
 
 
56482
/*
 
56483
 *  (Re)initialize the temporary byte buffer.  May be called extra times
 
56484
 *  with little impact.
 
56485
 */
 
56486
 
 
56487
static void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
 
56488
        if (lex_ctx->buf->usable_size < DUK_LEXER_TEMP_BUF_LIMIT) {
 
56489
                /* Resize (zero) without realloc. */
 
56490
                lex_ctx->buf->size = 0;
 
56491
        } else {
 
56492
                duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, 0, DUK_LEXER_TEMP_BUF_LIMIT);
 
56493
        }
 
56494
}
 
56495
 
 
56496
/*
 
56497
 *  Append a Unicode codepoint to the temporary byte buffer.  Performs
 
56498
 *  CESU-8 surrogate pair encoding for codepoints above the BMP.
 
56499
 *  Existing surrogate pairs are allowed and also encoded into CESU-8.
 
56500
 */
 
56501
 
 
56502
static void duk__appendbuffer(duk_lexer_ctx *lex_ctx, int x) {
 
56503
        /*
 
56504
         *  Since character data is only generated by decoding the source or by
 
56505
         *  the compiler itself, we rely on the input codepoints being correct
 
56506
         *  and avoid a check here.
 
56507
         *
 
56508
         *  Character data can also come here through decoding of Unicode
 
56509
         *  escapes ("\udead\ubeef") so all 16-but unsigned values can be
 
56510
         *  present, even when the source file itself is strict UTF-8.
 
56511
         */
 
56512
 
 
56513
        DUK_ASSERT(x >= 0 && x <= 0x10ffff);
 
56514
 
 
56515
        duk_hbuffer_append_cesu8(lex_ctx->thr, lex_ctx->buf, x);
 
56516
}
 
56517
 
 
56518
/*
 
56519
 *  Intern the temporary byte buffer into a valstack slot
 
56520
 *  (in practice, slot1 or slot2).
 
56521
 */
 
56522
 
 
56523
static void duk__internbuffer(duk_lexer_ctx *lex_ctx, int valstack_idx) {
 
56524
        duk_context *ctx = (duk_context *) lex_ctx->thr;
 
56525
 
 
56526
        DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
 
56527
 
 
56528
        duk_dup(ctx, lex_ctx->buf_idx);
 
56529
        duk_to_string(ctx, -1);
 
56530
        duk_replace(ctx, valstack_idx);
 
56531
}
 
56532
 
 
56533
/*
 
56534
 *  Init lexer context
 
56535
 */
 
56536
 
 
56537
void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
 
56538
        DUK_ASSERT(lex_ctx != NULL);
 
56539
 
 
56540
        DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx));
 
56541
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
56542
        lex_ctx->thr = NULL;
 
56543
        lex_ctx->input = NULL;
 
56544
        lex_ctx->buf = NULL;
 
56545
#endif
 
56546
}
 
56547
 
 
56548
/*
 
56549
 *  Set lexer input position and reinitialize lookup window.
 
56550
 */
 
56551
 
 
56552
/* NB: duk_lexer_getpoint() is a macro only */
 
56553
 
 
56554
void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
 
56555
        DUK_ASSERT(pt->offset >= 0);
 
56556
        DUK_ASSERT(pt->line >= 1);
 
56557
        lex_ctx->input_offset = pt->offset;
 
56558
        lex_ctx->input_line = pt->line;
 
56559
        duk__advance_chars(lex_ctx, DUK_LEXER_WINDOW_SIZE);  /* fill window */
 
56560
}
 
56561
 
 
56562
/*
 
56563
 *  Lexing helpers
 
56564
 */
 
56565
 
 
56566
/* numeric value of a hex digit (also covers octal and decimal digits) */
 
56567
static int duk__hexval(duk_lexer_ctx *lex_ctx, int x) {
 
56568
        if (x >= '0' && x <= '9') {
 
56569
                return ((int) x) - ((int) '0');
 
56570
        } else if (x >= 'a' && x <= 'f') {
 
56571
                return ((int) x) - ((int) 'a') + 0x0a;
 
56572
        } else if (x >= 'A' && x <= 'F') {
 
56573
                return ((int) x) - ((int) 'A') + 0x0a;
 
56574
        }
 
56575
 
 
56576
        /* Throwing an error this deep makes the error rather vague, but
 
56577
         * saves hundreds of bytes of code.
 
56578
         */
 
56579
        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "decode error");
 
56580
        return 0;
 
56581
}
 
56582
 
 
56583
/* having this as a separate function provided a size benefit */
 
56584
static int duk__is_hex_digit(int x) {
 
56585
        return (x >= '0' && x <= '9') ||
 
56586
               (x >= 'a' && x <= 'f') ||
 
56587
               (x >= 'A' && x <= 'F');
 
56588
}
 
56589
 
 
56590
static int duk__decode_hexesc_from_window(duk_lexer_ctx *lex_ctx, int lookup_offset) {
 
56591
        /* validation performed by duk__hexval */
 
56592
        return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset]) << 4) |
 
56593
               (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1]));
 
56594
}
 
56595
 
 
56596
static int duk__decode_uniesc_from_window(duk_lexer_ctx *lex_ctx, int lookup_offset) {
 
56597
        /* validation performed by duk__hexval */
 
56598
        return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset]) << 12) |
 
56599
               (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1]) << 8) |
 
56600
               (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 2]) << 4) |
 
56601
               (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 3]));
 
56602
}
 
56603
 
 
56604
/*
 
56605
 *  Eat input characters until first character of window is not
 
56606
 *  a white space (may be -1 if EOF encountered).
 
56607
 */
 
56608
static void duk__eat_whitespace(duk_lexer_ctx *lex_ctx) {
 
56609
        /* guaranteed to finish, as EOF (-1) is not a whitespace */
 
56610
        while (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
 
56611
                DUK__ADVANCE(lex_ctx, 1);
 
56612
        }
 
56613
}
 
56614
 
 
56615
/*
 
56616
 *  Parse Ecmascript source InputElementDiv or InputElementRegExp
 
56617
 *  (E5 Section 7).
 
56618
 *
 
56619
 *  Possible results are:
 
56620
 *    (1) a token
 
56621
 *    (2) a line terminator
 
56622
 *    (3) a comment
 
56623
 *    (4) EOF
 
56624
 *
 
56625
 *  White space is automatically skipped from the current position (but
 
56626
 *  not after the input element).  If input has already ended, returns
 
56627
 *  DUK_TOK_EOF indefinitely.  If a parse error occurs, uses an DUK_ERROR()
 
56628
 *  macro call (and hence a longjmp through current heap longjmp context).
 
56629
 *
 
56630
 *  The input element being matched is determined by regexp_mode; if set,
 
56631
 *  parses a InputElementRegExp, otherwise a InputElementDiv.  The
 
56632
 *  difference between these are handling of productions starting with a
 
56633
 *  forward slash.
 
56634
 *
 
56635
 *  If strict_mode is set, recognizes additional future reserved words
 
56636
 *  specific to strict mode, and refuses to parse octal literals.
 
56637
 *
 
56638
 *  The matching strategy below is to (currently) use a six character
 
56639
 *  lookup window to quickly determine which production is the -longest-
 
56640
 *  matching one, and then parse that.  The top-level if-else clauses
 
56641
 *  match the first character, and the code blocks for each clause
 
56642
 *  handle -all- alternatives for that first character.  Ecmascript
 
56643
 *  specification uses the "longest match wins" semantics, so the order
 
56644
 *  of the if-clauses matters.
 
56645
 *
 
56646
 *  Misc notes:
 
56647
 *
 
56648
 *    * Ecmascript numeric literals do not accept a sign character.
 
56649
 *      Consequently e.g. "-1.0" is parsed as two tokens: a negative
 
56650
 *      sign and a positive numeric literal.  The compiler performs
 
56651
 *      the negation during compilation, so this has no adverse impact.
 
56652
 *
 
56653
 *    * There is no token for "undefined": it is just a value available
 
56654
 *      from the global object (or simply established by doing a reference
 
56655
 *      to an undefined value).
 
56656
 *
 
56657
 *    * Some contexts want Identifier tokens, which are IdentifierNames
 
56658
 *      excluding reserved words, while some contexts want IdentifierNames
 
56659
 *      directly.  In the latter case e.g. "while" is interpreted as an
 
56660
 *      identifier name, not a DUK_TOK_WHILE token.  The solution here is
 
56661
 *      to provide both token types: DUK_TOK_WHILE goes to 't' while
 
56662
 *      DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
 
56663
 *      the identifier / keyword name.
 
56664
 *
 
56665
 *    * Directive prologue needs to identify string literals such as
 
56666
 *      "use strict" and 'use strict', which are sensitive to line
 
56667
 *      continuations and escape sequences.  For instance, "use\u0020strict"
 
56668
 *      is a valid directive but is distinct from "use strict".  The solution
 
56669
 *      here is to decode escapes while tokenizing, but to keep track of the
 
56670
 *      number of escapes.  Directive detection can then check that the
 
56671
 *      number of escapes is zero.
 
56672
 *
 
56673
 *    * Comments are expressed as DUK_TOK_COMMENT tokens, with the type
 
56674
 *      (single- or multi-line) and contents of the comments lost.
 
56675
 *      Furthermore, multi-line comments with one or more internal
 
56676
 *      LineTerminator are treated as DUK_TOK_LINETERM to comply with
 
56677
 *      automatic semicolon insertion and to avoid complicating the
 
56678
 *      tokenization process.  See E5 Section 7.4.
 
56679
 */
 
56680
 
 
56681
static void duk__parse_input_element_raw(duk_lexer_ctx *lex_ctx,
 
56682
                                         duk_token *out_token,
 
56683
                                         int strict_mode,
 
56684
                                         int regexp_mode) {
 
56685
        int x, y;               /* temporaries, must be 32-bit to hold Unicode code points */
 
56686
        int advtok = 0;         /* (advance << 8) + token_type, updated at function end,
 
56687
                                 * init is unnecessary but suppresses "may be used uninitialized warnings
 
56688
                                 */
 
56689
 
 
56690
        if (++lex_ctx->token_count >= lex_ctx->token_limit) {
 
56691
                DUK_ERROR(lex_ctx->thr, DUK_ERR_RANGE_ERROR, "token limit");
 
56692
                return;  /* unreachable */
 
56693
        }
 
56694
 
 
56695
        duk__eat_whitespace(lex_ctx);
 
56696
 
 
56697
        out_token->t = DUK_TOK_EOF;
 
56698
        out_token->t_nores = -1;        /* marker: copy t if not changed */
 
56699
        out_token->num = DUK_DOUBLE_NAN;
 
56700
        out_token->str1 = NULL;
 
56701
        out_token->str2 = NULL;
 
56702
        out_token->num_escapes = 0;
 
56703
        out_token->start_line = lex_ctx->lines[0];
 
56704
        out_token->start_offset = lex_ctx->offsets[0];
 
56705
        /* out_token->end_line set at exit */
 
56706
        /* out_token->lineterm set by caller */
 
56707
 
 
56708
        duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
 
56709
        duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
 
56710
 
 
56711
        /* 'advtok' indicates how much to advance and which token id to assign
 
56712
         * at the end.  This shared functionality minimizes code size.  All
 
56713
         * code paths are required to set 'advtok' to some value, so no default
 
56714
         * init value is used.  Code paths calling DUK_ERROR() never return so
 
56715
         * they don't need to set advtok.
 
56716
         */
 
56717
 
 
56718
        /*
 
56719
         *  Matching order:
 
56720
         *
 
56721
         *    Punctuator first chars, also covers comments, regexps
 
56722
         *    LineTerminator
 
56723
         *    Identifier or reserved word, also covers null/true/false literals
 
56724
         *    NumericLiteral
 
56725
         *    StringLiteral
 
56726
         *    EOF
 
56727
         *
 
56728
         *  The order does not matter as long as the longest match is
 
56729
         *  always correctly identified.  There are order dependencies
 
56730
         *  in the clauses, so it's not trivial to convert to a switch.
 
56731
         *
 
56732
         *  Maybe change this to a switch which handles all single character
 
56733
         *  cases and a follow-up if-else chain.  Switch matches need to goto
 
56734
         *  to bypass the if-else chain.
 
56735
         */
 
56736
 
 
56737
        x = DUK__L0();
 
56738
        y = DUK__L1();
 
56739
 
 
56740
        if (x == '/') {
 
56741
                if (y == '/') {
 
56742
                        /*
 
56743
                         *  E5 Section 7.4, allow SourceCharacter (which is any 16-bit
 
56744
                         *  code point).
 
56745
                         */
 
56746
 
 
56747
                        /* DUK__ADVANCE(lex_ctx, 2) would be correct here, but it unnecessary */
 
56748
                        for (;;) {
 
56749
                                x = DUK__L0();
 
56750
                                if (x < 0 || duk_unicode_is_line_terminator(x)) {
 
56751
                                        break;
 
56752
                                }
 
56753
                                DUK__ADVANCE(lex_ctx, 1);
 
56754
                        }
 
56755
                        advtok = DUK__ADVTOK(0, DUK_TOK_COMMENT);
 
56756
                } else if (y == '*') {
 
56757
                        /*
 
56758
                         *  E5 Section 7.4.  If the multi-line comment contains a newline,
 
56759
                         *  it is treated like a single DUK_TOK_LINETERM to facilitate
 
56760
                         *  automatic semicolon insertion.
 
56761
                         */
 
56762
 
 
56763
                        duk_uint8_t last_asterisk = 0;
 
56764
                        advtok = DUK__ADVTOK(0, DUK_TOK_COMMENT);
 
56765
                        DUK__ADVANCE(lex_ctx, 2);
 
56766
                        for (;;) {
 
56767
                                x = DUK__L0();
 
56768
                                if (x < 0) {
 
56769
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
56770
                                                  "eof while parsing multiline comment");
 
56771
                                }
 
56772
                                DUK__ADVANCE(lex_ctx, 1);
 
56773
                                if (last_asterisk && x == '/') {
 
56774
                                        break;
 
56775
                                }
 
56776
                                if (duk_unicode_is_line_terminator(x)) {
 
56777
                                        advtok = DUK__ADVTOK(0, DUK_TOK_LINETERM);
 
56778
                                }
 
56779
                                last_asterisk = (x == (int) '*');
 
56780
                        }
 
56781
                } else if (regexp_mode) {
 
56782
#ifdef DUK_USE_REGEXP_SUPPORT
 
56783
                        /*
 
56784
                         *  "/" followed by something in regexp mode.  See E5 Section 7.8.5.
 
56785
                         *
 
56786
                         *  RegExp parsing is a bit complex.  First, the regexp body is delimited
 
56787
                         *  by forward slashes, but the body may also contain forward slashes as
 
56788
                         *  part of an escape sequence or inside a character class (delimited by
 
56789
                         *  square brackets).  A mini state machine is used to implement these.
 
56790
                         *
 
56791
                         *  Further, an early (parse time) error must be thrown if the regexp
 
56792
                         *  would cause a run-time error when used in the expression new RegExp(...).
 
56793
                         *  Parsing here simply extracts the (candidate) regexp, and also accepts
 
56794
                         *  invalid regular expressions (which are delimited properly).  The caller
 
56795
                         *  (compiler) must perform final validation and regexp compilation.
 
56796
                         *
 
56797
                         *  RegExp first char may not be '/' (single line comment) or '*' (multi-
 
56798
                         *  line comment).  These have already been checked above, so there is no
 
56799
                         *  need below for special handling of the first regexp character as in
 
56800
                         *  the E5 productions.
 
56801
                         *
 
56802
                         *  About unicode escapes within regexp literals:
 
56803
                         *
 
56804
                         *      E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
 
56805
                         *      However, Section 6 states that regexps accept the escapes,
 
56806
                         *      see paragraph starting with "In string literals...".
 
56807
                         *      The regexp grammar, which sees the decoded regexp literal
 
56808
                         *      (after lexical parsing) DOES have a \uHHHH unicode escape.
 
56809
                         *      So, for instance:
 
56810
                         *
 
56811
                         *          /\u1234/
 
56812
                         *
 
56813
                         *      should first be parsed by the lexical grammar as:
 
56814
                         *
 
56815
                         *          '\' 'u'             RegularExpressionBackslashSequence
 
56816
                         *          '1'                 RegularExpressionNonTerminator
 
56817
                         *          '2'                 RegularExpressionNonTerminator
 
56818
                         *          '3'                 RegularExpressionNonTerminator
 
56819
                         *          '4'                 RegularExpressionNonTerminator
 
56820
                         *
 
56821
                         *      and the escape itself is then parsed by the regexp engine.
 
56822
                         *      This is the current implementation. 
 
56823
                         *
 
56824
                         *  Minor spec inconsistency:
 
56825
                         *
 
56826
                         *      E5 Section 7.8.5 RegularExpressionBackslashSequence is:
 
56827
                         *
 
56828
                         *         \ RegularExpressionNonTerminator
 
56829
                         *
 
56830
                         *      while Section A.1 RegularExpressionBackslashSequence is:
 
56831
                         *
 
56832
                         *         \ NonTerminator
 
56833
                         * 
 
56834
                         *      The latter is not normative and a typo.
 
56835
                         * 
 
56836
                         */
 
56837
 
 
56838
                        /* first, parse regexp body roughly */
 
56839
 
 
56840
                        duk_uint8_t state = 0;  /* 0=base, 1=esc, 2=class, 3=class+esc */
 
56841
 
 
56842
                        DUK__INITBUFFER(lex_ctx);
 
56843
                        for (;;) {
 
56844
                                DUK__ADVANCE(lex_ctx, 1);       /* skip opening slash on first loop */
 
56845
                                x = DUK__L0();
 
56846
                                if (x < 0 || duk_unicode_is_line_terminator(x)) {
 
56847
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
56848
                                                  "eof or line terminator while parsing regexp");
 
56849
                                }
 
56850
                                x = DUK__L0();  /* re-read to avoid spill / fetch */
 
56851
                                if (state == 0) {
 
56852
                                        if (x == '/') {
 
56853
                                                DUK__ADVANCE(lex_ctx, 1);       /* eat closing slash */
 
56854
                                                break;
 
56855
                                        } else if (x == '\\') {
 
56856
                                                state = 1;
 
56857
                                        } else if (x == '[') {
 
56858
                                                state = 2;
 
56859
                                        }
 
56860
                                } else if (state == 1) {
 
56861
                                        state = 0;
 
56862
                                } else if (state == 2) {
 
56863
                                        if (x == ']') {
 
56864
                                                state = 0;
 
56865
                                        } else if (x == '\\') {
 
56866
                                                state = 3;
 
56867
                                        }
 
56868
                                } else { /* state == 3 */
 
56869
                                        state = 2;
 
56870
                                }
 
56871
                                DUK__APPENDBUFFER(lex_ctx, x);
 
56872
                        }
 
56873
                        duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
 
56874
                        out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
 
56875
 
 
56876
                        /* second, parse flags */
 
56877
 
 
56878
                        DUK__INITBUFFER(lex_ctx);
 
56879
                        for (;;) {
 
56880
                                x = DUK__L0();
 
56881
                                if (!duk_unicode_is_identifier_part(x)) {
 
56882
                                        break;
 
56883
                                }
 
56884
                                x = DUK__L0();  /* re-read to avoid spill / fetch */
 
56885
                                DUK__APPENDBUFFER(lex_ctx, x);
 
56886
                                DUK__ADVANCE(lex_ctx, 1);
 
56887
                        }
 
56888
                        duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
 
56889
                        out_token->str2 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
 
56890
 
 
56891
                        DUK__INITBUFFER(lex_ctx);       /* free some memory */
 
56892
 
 
56893
                        /* validation of the regexp is caller's responsibility */
 
56894
 
 
56895
                        advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
 
56896
#else
 
56897
                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "regexp support disabled");
 
56898
#endif
 
56899
                } else if (y == '=') {
 
56900
                        /* "/=" and not in regexp mode */
 
56901
                        advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
 
56902
                } else {
 
56903
                        /* "/" and not in regexp mode */
 
56904
                        advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
 
56905
                }
 
56906
        } else if (x == '{') {
 
56907
                advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
 
56908
        } else if (x == '}') {
 
56909
                advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
 
56910
        } else if (x == '(') {
 
56911
                advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
 
56912
        } else if (x == ')') {
 
56913
                advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
 
56914
        } else if (x == '[') {
 
56915
                advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
 
56916
        } else if (x == ']') {
 
56917
                advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
 
56918
        } else if (x == '.' && !DUK__ISDIGIT(y)) {
 
56919
                /* Note: period followed by a digit can only start DecimalLiteral (captured below) */
 
56920
                advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
 
56921
        } else if (x == ';') {
 
56922
                advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
 
56923
        } else if (x == ',') {
 
56924
                advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
 
56925
        } else if (x == '<') {
 
56926
                if (y == '<' && DUK__L2() == '=') {
 
56927
                        advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
 
56928
                } else if (y == '=') {
 
56929
                        advtok = DUK__ADVTOK(2, DUK_TOK_LE);
 
56930
                } else if (y == '<') {
 
56931
                        advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
 
56932
                } else {
 
56933
                        advtok = DUK__ADVTOK(1, DUK_TOK_LT);
 
56934
                }
 
56935
        } else if (x == '>') {
 
56936
                if (y == '>' && DUK__L2() == '>' && DUK__L3() == '=') {
 
56937
                        advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
 
56938
                } else if (y == '>' && DUK__L2() == '>') {
 
56939
                        advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
 
56940
                } else if (y == '>' && DUK__L2() == '=') {
 
56941
                        advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
 
56942
                } else if (y == '=') {
 
56943
                        advtok = DUK__ADVTOK(2, DUK_TOK_GE);
 
56944
                } else if (y == '>') {
 
56945
                        advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
 
56946
                } else {
 
56947
                        advtok = DUK__ADVTOK(1, DUK_TOK_GT);
 
56948
                }
 
56949
        } else if (x == '=') {
 
56950
                if (y == '=' && DUK__L2() == '=') {
 
56951
                        advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
 
56952
                } else if (y == '=') {
 
56953
                        advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
 
56954
                } else {
 
56955
                        advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
 
56956
                }
 
56957
        } else if (x == '!') {
 
56958
                if (y == '=' && DUK__L2() == '=') {
 
56959
                        advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
 
56960
                } else if (y == '=') {
 
56961
                        advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
 
56962
                } else {
 
56963
                        advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
 
56964
                }
 
56965
        } else if (x == '+') {
 
56966
                if (y == '+') {
 
56967
                        advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
 
56968
                } else if (y == '=') {
 
56969
                        advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
 
56970
                } else {
 
56971
                        advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
 
56972
                }
 
56973
        } else if (x == '-') {
 
56974
                if (y == '-') {
 
56975
                        advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
 
56976
                } else if (y == '=') {
 
56977
                        advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
 
56978
                } else {
 
56979
                        advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
 
56980
                }
 
56981
        } else if (x == '*') {
 
56982
                if (y == '=') {
 
56983
                        advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
 
56984
                } else {
 
56985
                        advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
 
56986
                }
 
56987
        } else if (x == '%') {
 
56988
                if (y == '=') {
 
56989
                        advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
 
56990
                } else {
 
56991
                        advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
 
56992
                }
 
56993
        } else if (x == '&') {
 
56994
                if (y == '&') {
 
56995
                        advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
 
56996
                } else if (y == '=') {
 
56997
                        advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
 
56998
                } else {
 
56999
                        advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
 
57000
                }
 
57001
        } else if (x == '|') {
 
57002
                if (y == '|') {
 
57003
                        advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
 
57004
                } else if (y == '=') {
 
57005
                        advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
 
57006
                } else {
 
57007
                        advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
 
57008
                }
 
57009
        } else if (x == '^') {
 
57010
                if (y == '=') {
 
57011
                        advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
 
57012
                } else {
 
57013
                        advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
 
57014
                }
 
57015
        } else if (x == '~') {
 
57016
                advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
 
57017
        } else if (x == '?') {
 
57018
                advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
 
57019
        } else if (x == ':') {
 
57020
                advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
 
57021
        } else if (duk_unicode_is_line_terminator(x)) {
 
57022
                if (x == 0x000d && y == 0x000a) {
 
57023
                        /*
 
57024
                         *  E5 Section 7.3: CR LF is detected as a single line terminator for
 
57025
                         *  line numbers.  Here we also detect it as a single line terminator
 
57026
                         *  token.
 
57027
                         */
 
57028
                        advtok = DUK__ADVTOK(2, DUK_TOK_LINETERM);
 
57029
                } else {
 
57030
                        advtok = DUK__ADVTOK(1, DUK_TOK_LINETERM);
 
57031
                }
 
57032
        } else if (duk_unicode_is_identifier_start(x) || x == '\\') {
 
57033
                /*
 
57034
                 *  Parse an identifier and then check whether it is:
 
57035
                 *    - reserved word (keyword or other reserved word)
 
57036
                 *    - "null"  (NullLiteral)
 
57037
                 *    - "true"  (BooleanLiteral)
 
57038
                 *    - "false" (BooleanLiteral)
 
57039
                 *    - anything else => identifier
 
57040
                 *
 
57041
                 *  This does not follow the E5 productions cleanly, but is
 
57042
                 *  useful and compact.
 
57043
                 *
 
57044
                 *  Note that identifiers may contain Unicode escapes,
 
57045
                 *  see E5 Sections 6 and 7.6.  They must be decoded first,
 
57046
                 *  and the result checked against allowed characters.
 
57047
                 *  The above if-clause accepts an identifier start and an
 
57048
                 *  '\' character -- no other token can begin with a '\'.
 
57049
                 *
 
57050
                 *  Note that "get" and "set" are not reserved words in E5
 
57051
                 *  specification so they are recognized as plain identifiers
 
57052
                 *  (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
 
57053
                 *  used now).  The compiler needs to work around this.
 
57054
                 *
 
57055
                 *  Strictly speaking, following Ecmascript longest match
 
57056
                 *  specification, an invalid escape for the first character
 
57057
                 *  should cause a syntax error.  However, an invalid escape
 
57058
                 *  for IdentifierParts should just terminate the identifier
 
57059
                 *  early (longest match), and let the next tokenization
 
57060
                 *  fail.  For instance Rhino croaks with 'foo\z' when
 
57061
                 *  parsing the identifier.  This has little practical impact.
 
57062
                 */
 
57063
 
 
57064
                int i, i_end;
 
57065
                int first = 1;
 
57066
                duk_hstring *str;
 
57067
 
 
57068
                DUK__INITBUFFER(lex_ctx);
 
57069
                for (;;) {
 
57070
                        /* re-lookup first char on first loop */
 
57071
                        if (DUK__L0() == '\\') {
 
57072
                                int ch;
 
57073
                                if (DUK__L1() != 'u') {
 
57074
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57075
                                                  "invalid unicode escape while parsing identifier");
 
57076
                                }
 
57077
 
 
57078
                                ch = duk__decode_uniesc_from_window(lex_ctx, 2);
 
57079
 
 
57080
                                /* IdentifierStart is stricter than IdentifierPart, so if the first
 
57081
                                 * character is escaped, must have a stricter check here.
 
57082
                                 */
 
57083
                                if (! (first ? duk_unicode_is_identifier_start(ch) : duk_unicode_is_identifier_part(ch))) {
 
57084
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57085
                                                  "invalid unicode escaped character while parsing identifier");
 
57086
                                }
 
57087
                                DUK__APPENDBUFFER(lex_ctx, ch);
 
57088
                                DUK__ADVANCE(lex_ctx, 6);
 
57089
 
 
57090
                                /* Track number of escapes: necessary for proper keyword
 
57091
                                 * detection.
 
57092
                                 */
 
57093
                                out_token->num_escapes++;
 
57094
                        } else {
 
57095
                                /* Note: first character is checked against this.  But because
 
57096
                                 * IdentifierPart includes all IdentifierStart characters, and
 
57097
                                 * the first character (if unescaped) has already been checked
 
57098
                                 * in the if condition, this is OK.
 
57099
                                 */
 
57100
                                if (!duk_unicode_is_identifier_part(DUK__L0())) {
 
57101
                                        break;
 
57102
                                }
 
57103
                                DUK__APPENDBUFFER(lex_ctx, DUK__L0());
 
57104
                                DUK__ADVANCE(lex_ctx, 1);
 
57105
                        }
 
57106
                        first = 0;
 
57107
                }
 
57108
 
 
57109
                duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
 
57110
                out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
 
57111
                str = out_token->str1;
 
57112
                DUK_ASSERT(str != NULL);
 
57113
                out_token->t_nores = DUK_TOK_IDENTIFIER;
 
57114
 
 
57115
                DUK__INITBUFFER(lex_ctx);       /* free some memory */
 
57116
 
 
57117
                /*
 
57118
                 *  Interned identifier is compared against reserved words, which are
 
57119
                 *  currently interned into the heap context.  See genstrings.py.
 
57120
                 *
 
57121
                 *  Note that an escape in the identifier disables recognition of
 
57122
                 *  keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
 
57123
                 *  identifier named "if").  This is not necessarily compliant,
 
57124
                 *  see test-dec-escaped-char-in-keyword.js.
 
57125
                 *
 
57126
                 *  Note: "get" and "set" are awkward.  They are not officially
 
57127
                 *  ReservedWords (and indeed e.g. "var set = 1;" is valid), and
 
57128
                 *  must come out as DUK_TOK_IDENTIFIER.  The compiler needs to
 
57129
                 *  work around this a bit.
 
57130
                 */
 
57131
 
 
57132
                i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
 
57133
 
 
57134
                advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
 
57135
                if (out_token->num_escapes == 0) {
 
57136
                        for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
 
57137
                                DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
 
57138
                                if (lex_ctx->thr->strs[i] == str) {
 
57139
                                        advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
 
57140
                                        break;
 
57141
                                }
 
57142
                        }
 
57143
                }
 
57144
        } else if (DUK__ISDIGIT(x) || (x == '.')) {
 
57145
                /* Note: decimal number may start with a period, but must be followed by a digit */
 
57146
 
 
57147
                /*
 
57148
                 *  DecimalLiteral, HexIntegerLiteral, OctalIntegerLiteral
 
57149
                 *  "pre-parsing", followed by an actual, accurate parser step.
 
57150
                 *
 
57151
                 *  Note: the leading sign character ('+' or '-') is -not- part of
 
57152
                 *  the production in E5 grammar, and that the a DecimalLiteral
 
57153
                 *  starting with a '0' must be followed by a non-digit.  Leading
 
57154
                 *  zeroes are syntax errors and must be checked for.
 
57155
                 *
 
57156
                 *  XXX: the two step parsing process is quite awkward, it would
 
57157
                 *  be more straightforward to allow numconv to parse the longest
 
57158
                 *  valid prefix (it already does that, it only needs to indicate
 
57159
                 *  where the input ended).  However, the lexer decodes characters
 
57160
                 *  using a lookup window, so this is not a trivial change.
 
57161
                 */
 
57162
 
 
57163
                /* XXX: because of the final check below (that the literal is not
 
57164
                 * followed by a digit), this could maybe be simplified, if we bail
 
57165
                 * out early from a leading zero (and if there are no periods etc).
 
57166
                 * Maybe too complex.
 
57167
                 */
 
57168
 
 
57169
                double val;
 
57170
                int int_only = 0;
 
57171
                int allow_hex = 0;
 
57172
                int st;         /* 0=before period/exp,
 
57173
                                 * 1=after period, before exp
 
57174
                                 * 2=after exp, allow '+' or '-'
 
57175
                                 * 3=after exp and exp sign
 
57176
                                 */
 
57177
                int s2n_flags;
 
57178
 
 
57179
                DUK__INITBUFFER(lex_ctx);
 
57180
                if (x == '0' && (y == 'x' || y == 'X')) {
 
57181
                        DUK__APPENDBUFFER(lex_ctx, x);
 
57182
                        DUK__APPENDBUFFER(lex_ctx, y);
 
57183
                        DUK__ADVANCE(lex_ctx, 2);
 
57184
                        int_only = 1;
 
57185
                        allow_hex = 1;
 
57186
#ifdef DUK_USE_OCTAL_SUPPORT
 
57187
                } else if (!strict_mode && x == '0' && DUK__ISDIGIT(y)) {
 
57188
                        /* Note: if DecimalLiteral starts with a '0', it can only be
 
57189
                         * followed by a period or an exponent indicator which starts
 
57190
                         * with 'e' or 'E'.  Hence the if-check above ensures that
 
57191
                         * OctalIntegerLiteral is the only valid NumericLiteral
 
57192
                         * alternative at this point (even if y is, say, '9').
 
57193
                         */
 
57194
        
 
57195
                        DUK__APPENDBUFFER(lex_ctx, x);
 
57196
                        DUK__ADVANCE(lex_ctx, 1);
 
57197
                        int_only = 1;
 
57198
#endif
 
57199
                }
 
57200
 
 
57201
                st = 0;
 
57202
                for (;;) {
 
57203
                        x = DUK__L0();  /* re-lookup curr char on first round */
 
57204
                        if (DUK__ISDIGIT(x)) {
 
57205
                                /* Note: intentionally allow leading zeroes here, as the
 
57206
                                 * actual parser will check for them.
 
57207
                                 */
 
57208
                                if (st == 2) {
 
57209
                                        st = 3;
 
57210
                                }
 
57211
                        } else if (allow_hex && DUK__ISHEXDIGIT(x)) {
 
57212
                                /* Note: 'e' and 'E' are also accepted here. */
 
57213
                                ;
 
57214
                        } else if (x == '.') {
 
57215
                                if (st >= 1 || int_only) {
 
57216
                                        break;
 
57217
                                } else {
 
57218
                                        st = 1;
 
57219
                                }
 
57220
                        } else if (x == 'e' || x == 'E') {
 
57221
                                if (st >= 2 || int_only) {
 
57222
                                        break;
 
57223
                                } else {
 
57224
                                        st = 2;
 
57225
                                }
 
57226
                        } else if (x == '-' || x == '+') {
 
57227
                                if (st != 2) {
 
57228
                                        break;
 
57229
                                } else {
 
57230
                                        st = 3;
 
57231
                                }
 
57232
                        } else {
 
57233
                                break;
 
57234
                        }
 
57235
                        DUK__APPENDBUFFER(lex_ctx, x);
 
57236
                        DUK__ADVANCE(lex_ctx, 1);
 
57237
                }
 
57238
 
 
57239
                /* FIXME: better coercion */
 
57240
                duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
 
57241
 
 
57242
                s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
 
57243
                            DUK_S2N_FLAG_ALLOW_FRAC |
 
57244
                            DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
 
57245
                            DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
 
57246
#ifdef DUK_USE_OCTAL_SUPPORT
 
57247
                            (strict_mode ? 0 : DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) |
 
57248
#endif
 
57249
                            DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
 
57250
 
 
57251
                duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
 
57252
                duk_numconv_parse((duk_context *) lex_ctx->thr, 10 /*radix*/, s2n_flags);
 
57253
                val = duk_to_number((duk_context *) lex_ctx->thr, -1);
 
57254
                if (DUK_ISNAN(val)) {
 
57255
                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "invalid numeric literal");
 
57256
                }
 
57257
                duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);  /* FIXME: or pop? */
 
57258
 
 
57259
                DUK__INITBUFFER(lex_ctx);       /* free some memory */
 
57260
 
 
57261
                /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
 
57262
                 * IdentifierStart or DecimalDigit.
 
57263
                 */
 
57264
 
 
57265
                if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
 
57266
                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "invalid numeric literal");
 
57267
                }
 
57268
 
 
57269
                out_token->num = val;
 
57270
                advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
 
57271
        } else if (x == '"' || x == '\'') {
 
57272
                int quote = x;  /* duk_uint8_t type yields larger code */
 
57273
                int adv;
 
57274
 
 
57275
                DUK__INITBUFFER(lex_ctx);
 
57276
                for (;;) {
 
57277
                        DUK__ADVANCE(lex_ctx, 1);       /* eat opening quote on first loop */
 
57278
                        x = DUK__L0();
 
57279
                        if (x < 0 || duk_unicode_is_line_terminator(x)) {
 
57280
                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57281
                                          "eof or line terminator while parsing string literal");
 
57282
                        }
 
57283
                        if (x == quote) {
 
57284
                                DUK__ADVANCE(lex_ctx, 1);       /* eat closing quote */
 
57285
                                break;
 
57286
                        }
 
57287
                        if (x == '\\') {
 
57288
                                /* DUK__L0        -> '\' char
 
57289
                                 * DUK__L1 ... DUK__L5 -> more lookup
 
57290
                                 */
 
57291
 
 
57292
                                x = DUK__L1();
 
57293
                                y = DUK__L2();
 
57294
 
 
57295
                                /* How much to advance before next loop; note that next loop
 
57296
                                 * will advance by 1 anyway, so -1 from the total escape
 
57297
                                 * length (e.g. len('\uXXXX') - 1 = 6 - 1).  As a default,
 
57298
                                 * 1 is good.
 
57299
                                 */
 
57300
                                adv = 2 - 1;    /* note: long live range */
 
57301
 
 
57302
                                if (x < 0) {
 
57303
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57304
                                                  "eof while parsing string literal");
 
57305
                                }
 
57306
                                if (duk_unicode_is_line_terminator(x)) {
 
57307
                                        /* line continuation */
 
57308
                                        if (x == 0x000d && y == 0x000a) {
 
57309
                                                /* CR LF again a special case */
 
57310
                                                adv = 3 - 1;
 
57311
                                        }
 
57312
                                } else if (x == '\'') {
 
57313
                                        DUK__APPENDBUFFER(lex_ctx, 0x0027);
 
57314
                                } else if (x == '"') {
 
57315
                                        DUK__APPENDBUFFER(lex_ctx, 0x0022);
 
57316
                                } else if (x == '\\') {
 
57317
                                        DUK__APPENDBUFFER(lex_ctx, 0x005c);
 
57318
                                } else if (x == 'b') {
 
57319
                                        DUK__APPENDBUFFER(lex_ctx, 0x0008);
 
57320
                                } else if (x == 'f') {
 
57321
                                        DUK__APPENDBUFFER(lex_ctx, 0x000c);
 
57322
                                } else if (x == 'n') {
 
57323
                                        DUK__APPENDBUFFER(lex_ctx, 0x000a);
 
57324
                                } else if (x == 'r') {
 
57325
                                        DUK__APPENDBUFFER(lex_ctx, 0x000d);
 
57326
                                } else if (x == 't') {
 
57327
                                        DUK__APPENDBUFFER(lex_ctx, 0x0009);
 
57328
                                } else if (x == 'v') {
 
57329
                                        DUK__APPENDBUFFER(lex_ctx, 0x000b);
 
57330
                                } else if (x == 'x') {
 
57331
                                        adv = 4 - 1;
 
57332
                                        DUK__APPENDBUFFER(lex_ctx, duk__decode_hexesc_from_window(lex_ctx, 2));
 
57333
                                } else if (x == 'u') {
 
57334
                                        adv = 6 - 1;
 
57335
                                        DUK__APPENDBUFFER(lex_ctx, duk__decode_uniesc_from_window(lex_ctx, 2));
 
57336
                                } else if (DUK__ISDIGIT(x)) {
 
57337
                                        int ch = 0;  /* initialized to avoid warnings of unused var */
 
57338
 
 
57339
                                        /*
 
57340
                                         *  Octal escape or zero escape:
 
57341
                                         *    \0                                     (lookahead not DecimalDigit)
 
57342
                                         *    \1 ... \7                              (lookahead not DecimalDigit)
 
57343
                                         *    \ZeroToThree OctalDigit                (lookahead not DecimalDigit)
 
57344
                                         *    \FourToSeven OctalDigit                (no lookahead restrictions)
 
57345
                                         *    \ZeroToThree OctalDigit OctalDigit     (no lookahead restrictions)
 
57346
                                         *
 
57347
                                         *  Zero escape is part of the standard syntax.  Octal escapes are
 
57348
                                         *  defined in E5 Section B.1.2, and are only allowed in non-strict mode.
 
57349
                                         *  Any other productions starting with a decimal digit are invalid.
 
57350
                                         */
 
57351
 
 
57352
                                        if (x == '0' && !DUK__ISDIGIT(y)) {
 
57353
                                                /* Zero escape (also allowed in non-strict mode) */
 
57354
                                                ch = 0;
 
57355
                                                /* adv = 2 - 1 default OK */
 
57356
#ifdef DUK_USE_OCTAL_SUPPORT
 
57357
                                        } else if (strict_mode) {
 
57358
                                                /* No other escape beginning with a digit in strict mode */
 
57359
                                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57360
                                                          "invalid escape while parsing string literal");
 
57361
                                        } else if (DUK__ISDIGIT03(x) && DUK__ISOCTDIGIT(y) && DUK__ISOCTDIGIT(DUK__L3())) {
 
57362
                                                /* Three digit octal escape, digits validated. */
 
57363
                                                adv = 4 - 1;
 
57364
                                                ch = (duk__hexval(lex_ctx, x) << 6) +
 
57365
                                                     (duk__hexval(lex_ctx, y) << 3) +
 
57366
                                                     duk__hexval(lex_ctx, DUK__L3());
 
57367
                                        } else if (((DUK__ISDIGIT03(x) && !DUK__ISDIGIT(DUK__L3())) || DUK__ISDIGIT47(x)) &&
 
57368
                                                   DUK__ISOCTDIGIT(y)) {
 
57369
                                                /* Two digit octal escape, digits validated.
 
57370
                                                 * 
 
57371
                                                 * The if-condition is a bit tricky.  We could catch e.g.
 
57372
                                                 * '\039' in the three-digit escape and fail it there (by
 
57373
                                                 * validating the digits), but we want to avoid extra
 
57374
                                                 * additional validation code.
 
57375
                                                 */
 
57376
                                                adv = 3 - 1;
 
57377
                                                ch = (duk__hexval(lex_ctx, x) << 3) +
 
57378
                                                     duk__hexval(lex_ctx, y);
 
57379
                                        } else if (DUK__ISDIGIT(x) && !DUK__ISDIGIT(y)) {
 
57380
                                                /* One digit octal escape, digit validated. */
 
57381
                                                /* adv = 2 default OK */
 
57382
                                                ch = duk__hexval(lex_ctx, x);
 
57383
#else
 
57384
                                        /* fall through to error */
 
57385
#endif
 
57386
                                        } else {
 
57387
                                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57388
                                                          "invalid escape while parsing string literal");
 
57389
                                        }
 
57390
 
 
57391
                                        DUK__APPENDBUFFER(lex_ctx, ch);
 
57392
                                } else {
 
57393
                                        /* escaped NonEscapeCharacter */
 
57394
                                        DUK__APPENDBUFFER(lex_ctx, x);
 
57395
                                }
 
57396
                                DUK__ADVANCE(lex_ctx, adv);
 
57397
 
 
57398
                                /* Track number of escapes; count not really needed but directive
 
57399
                                 * prologues need to detect whether there were any escapes or line
 
57400
                                 * continuations or not.
 
57401
                                 */
 
57402
                                out_token->num_escapes++;
 
57403
                        } else {
 
57404
                                /* part of string */
 
57405
                                DUK__APPENDBUFFER(lex_ctx, x);
 
57406
                        }
 
57407
                }
 
57408
 
 
57409
                duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
 
57410
                out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
 
57411
 
 
57412
                DUK__INITBUFFER(lex_ctx);       /* free some memory */
 
57413
 
 
57414
                advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
 
57415
        } else if (x < 0) {
 
57416
                advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
 
57417
        } else {
 
57418
                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "error parsing token");
 
57419
        }
 
57420
 
 
57421
        /*
 
57422
         *  Shared exit path
 
57423
         */
 
57424
 
 
57425
        DUK__ADVANCE(lex_ctx, advtok >> 8);
 
57426
        out_token->t = advtok & 0xff;
 
57427
        if (out_token->t_nores < 0) {
 
57428
                out_token->t_nores = out_token->t;
 
57429
        }
 
57430
        out_token->end_line = lex_ctx->lines[0];
 
57431
}
 
57432
 
 
57433
/*
 
57434
 *  Tokenize input until a non-whitespace, non-lineterm token is found.
 
57435
 *  Note in the output token whether a lineterm token preceded the starting
 
57436
 *  point (inclusive) and the result token.  This information is needed for
 
57437
 *  automatic semicolon insertion.
 
57438
 *
 
57439
 *  Future work:
 
57440
 *
 
57441
 *    * Merge with duk__parse_input_element_raw() because only this function is
 
57442
 *      called in practice.
 
57443
 */
 
57444
 
 
57445
/* FIXME: change mode flags into one flags argument? */
 
57446
 
 
57447
void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
 
57448
                                      duk_token *out_token,
 
57449
                                      int strict_mode,
 
57450
                                      int regexp_mode) {
 
57451
        int tok;
 
57452
        int got_lineterm = 0;  /* got lineterm preceding non-whitespace, non-lineterm token */
 
57453
 
 
57454
        for (;;) {
 
57455
                duk__parse_input_element_raw(lex_ctx, out_token, strict_mode, regexp_mode);
 
57456
                tok = out_token->t;
 
57457
 
 
57458
                DUK_DDDPRINT("RAWTOKEN: %d (line %d-%d)",
 
57459
                             tok, out_token->start_line, out_token->end_line);
 
57460
 
 
57461
                if (tok == DUK_TOK_COMMENT) {
 
57462
                        /* single-line comment or multi-line comment without an internal lineterm */
 
57463
                        continue;
 
57464
                } else if (tok == DUK_TOK_LINETERM) {
 
57465
                        /* lineterm or multi-line comment with an internal lineterm */
 
57466
                        got_lineterm = 1;
 
57467
                        continue;
 
57468
                } else {
 
57469
                        break;
 
57470
                }
 
57471
        }
 
57472
 
 
57473
        out_token->lineterm = got_lineterm;
 
57474
 
 
57475
        /* Automatic semicolon insertion is allowed if a token is preceded
 
57476
         * by line terminator(s), or terminates a statement list (right curly
 
57477
         * or EOF).
 
57478
         */
 
57479
        if (got_lineterm || tok == DUK_TOK_RCURLY || tok == DUK_TOK_EOF) {
 
57480
                out_token->allow_auto_semi = 1;
 
57481
        } else {
 
57482
                out_token->allow_auto_semi = 0;
 
57483
        }
 
57484
}
 
57485
 
 
57486
#ifdef DUK_USE_REGEXP_SUPPORT
 
57487
 
 
57488
/*
 
57489
 *  Parse a RegExp token.  The grammar is described in E5 Section 15.10.
 
57490
 *  Terminal constructions (such as quantifiers) are parsed directly here.
 
57491
 *
 
57492
 *  0xffffffffU is used as a marker for "infinity" in quantifiers.  Further,
 
57493
 *  DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
 
57494
 *  will be accepted for a quantifier.
 
57495
 */
 
57496
 
 
57497
void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
 
57498
        int advtok = 0;  /* init is unnecessary but suppresses "may be used uninitialized" warnings */
 
57499
        int x, y;
 
57500
 
 
57501
        if (++lex_ctx->token_count >= lex_ctx->token_limit) {
 
57502
                DUK_ERROR(lex_ctx->thr, DUK_ERR_RANGE_ERROR, "token limit");
 
57503
                return;  /* unreachable */
 
57504
        }
 
57505
 
 
57506
        DUK_MEMZERO(out_token, sizeof(*out_token));
 
57507
 
 
57508
        x = DUK__L0();
 
57509
        y = DUK__L1();
 
57510
 
 
57511
        DUK_DDDPRINT("parsing regexp token, L0=%d, L1=%d", x, y);
 
57512
 
 
57513
        switch (x) {
 
57514
        case '|': {
 
57515
                advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
 
57516
                break;
 
57517
        }
 
57518
        case '^': {
 
57519
                advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
 
57520
                break;
 
57521
        }
 
57522
        case '$': {
 
57523
                advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
 
57524
                break;
 
57525
        }
 
57526
        case '?': {
 
57527
                out_token->qmin = 0;
 
57528
                out_token->qmax = 1;    
 
57529
                if (y == '?') {
 
57530
                        advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
 
57531
                        out_token->greedy = 0;
 
57532
                } else {
 
57533
                        advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
 
57534
                        out_token->greedy = 1;
 
57535
                }
 
57536
                break;
 
57537
        }
 
57538
        case '*': {
 
57539
                out_token->qmin = 0;
 
57540
                out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
 
57541
                if (y == '?') {
 
57542
                        advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
 
57543
                        out_token->greedy = 0;
 
57544
                } else {
 
57545
                        advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
 
57546
                        out_token->greedy = 1;
 
57547
                }
 
57548
                break;
 
57549
        }
 
57550
        case '+': {
 
57551
                out_token->qmin = 1;
 
57552
                out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
 
57553
                if (y == '?') {
 
57554
                        advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
 
57555
                        out_token->greedy = 0;
 
57556
                } else {
 
57557
                        advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
 
57558
                        out_token->greedy = 1;
 
57559
                }
 
57560
                break;
 
57561
        }
 
57562
        case '{': {
 
57563
                /* Production allows 'DecimalDigits', including leading zeroes */
 
57564
                duk_uint32_t val1 = 0;
 
57565
                duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
 
57566
                int digits = 0;
 
57567
                for (;;) {
 
57568
                        DUK__ADVANCE(lex_ctx, 1);       /* eat '{' on entry */
 
57569
                        x = DUK__L0();
 
57570
                        if (DUK__ISDIGIT(x)) {
 
57571
                                if (digits >= DUK__MAX_RE_QUANT_DIGITS) {
 
57572
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57573
                                                  "invalid regexp quantifier (too many digits)");
 
57574
                                }
 
57575
                                digits++;
 
57576
                                val1 = val1 * 10 + duk__hexval(lex_ctx, x);
 
57577
                        } else if (x == ',') {
 
57578
                                if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
 
57579
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57580
                                                  "invalid regexp quantifier (double comma)");
 
57581
                                }
 
57582
                                if (DUK__L1() == '}') {
 
57583
                                        /* form: { DecimalDigits , }, val1 = min count */
 
57584
                                        if (digits == 0) {
 
57585
                                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57586
                                                          "invalid regexp quantifier (missing digits)");
 
57587
                                        }
 
57588
                                        out_token->qmin = val1;
 
57589
                                        out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
 
57590
                                        DUK__ADVANCE(lex_ctx, 2);
 
57591
                                        break;
 
57592
                                }
 
57593
                                val2 = val1;
 
57594
                                val1 = 0;
 
57595
                                digits = 0;     /* not strictly necessary because of lookahead '}' above */
 
57596
                        } else if (x == '}') {
 
57597
                                if (digits == 0) {
 
57598
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57599
                                                  "invalid regexp quantifier (missing digits)");
 
57600
                                }
 
57601
                                if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
 
57602
                                        /* val2 = min count, val1 = max count */
 
57603
                                        out_token->qmin = val2;
 
57604
                                        out_token->qmax = val1;
 
57605
                                } else {
 
57606
                                        /* val1 = count */
 
57607
                                        out_token->qmin = val1;
 
57608
                                        out_token->qmax = val1;
 
57609
                                }
 
57610
                                DUK__ADVANCE(lex_ctx, 1);
 
57611
                                break;
 
57612
                        } else {
 
57613
                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57614
                                          "invalid regexp quantifier (unknown char)");
 
57615
                        }
 
57616
                }
 
57617
                if (DUK__L0() == '?') {
 
57618
                        out_token->greedy = 0;
 
57619
                        DUK__ADVANCE(lex_ctx, 1);
 
57620
                } else {
 
57621
                        out_token->greedy = 1;
 
57622
                }
 
57623
                advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
 
57624
                break;
 
57625
        }
 
57626
        case '.': {
 
57627
                advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
 
57628
                break;
 
57629
        }
 
57630
        case '\\': {
 
57631
                /* The E5.1 specification does not seem to allow IdentifierPart characters
 
57632
                 * to be used as identity escapes.  Unfortunately this includes '$', which
 
57633
                 * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
 
57634
                 * Many other implementations (including V8 and Rhino, for instance) do
 
57635
                 * accept '\$' as a valid identity escape, which is quite pragmatic.
 
57636
                 * See: test-regexp-identity-escape-dollar.js.
 
57637
                 */
 
57638
 
 
57639
                advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);   /* default: char escape (two chars) */
 
57640
                if (y == 'b') {
 
57641
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
 
57642
                } else if (y == 'B') {
 
57643
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
 
57644
                } else if (y == 'f') {
 
57645
                        out_token->num = 0x000c;
 
57646
                } else if (y == 'n') {
 
57647
                        out_token->num = 0x000a;
 
57648
                } else if (y == 't') {
 
57649
                        out_token->num = 0x0009;
 
57650
                } else if (y == 'r') {
 
57651
                        out_token->num = 0x000d;
 
57652
                } else if (y == 'v') {
 
57653
                        out_token->num = 0x000b;
 
57654
                } else if (y == 'c') {
 
57655
                        x = DUK__L2();
 
57656
                        if ((x >= 'a' && x <= 'z') ||
 
57657
                            (x >= 'A' && x <= 'Z')) {
 
57658
                                out_token->num = (x % 32);
 
57659
                                advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
 
57660
                        } else {
 
57661
                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57662
                                          "invalid regexp control escape");
 
57663
                        }
 
57664
                } else if (y == 'x') {
 
57665
                        out_token->num = duk__decode_hexesc_from_window(lex_ctx, 2);
 
57666
                        advtok = DUK__ADVTOK(4, DUK_RETOK_ATOM_CHAR);
 
57667
                } else if (y == 'u') {
 
57668
                        out_token->num = duk__decode_uniesc_from_window(lex_ctx, 2);
 
57669
                        advtok = DUK__ADVTOK(6, DUK_RETOK_ATOM_CHAR);
 
57670
                } else if (y == 'd') {
 
57671
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
 
57672
                } else if (y == 'D') {
 
57673
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
 
57674
                } else if (y == 's') {
 
57675
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
 
57676
                } else if (y == 'S') {
 
57677
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
 
57678
                } else if (y == 'w') {
 
57679
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
 
57680
                } else if (y == 'W') {
 
57681
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
 
57682
                } else if (DUK__ISDIGIT(y)) {
 
57683
                        /* E5 Section 15.10.2.11 */
 
57684
                        if (y == '0') {
 
57685
                                if (DUK__ISDIGIT(DUK__L2())) {
 
57686
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57687
                                                  "invalid regexp escape");
 
57688
                                }
 
57689
                                out_token->num = 0x0000;
 
57690
                                advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
 
57691
                        } else {
 
57692
                                /* FIXME: shared parsing? */
 
57693
                                duk_uint32_t val = 0;
 
57694
                                int i;
 
57695
                                for (i = 0; ; i++) {
 
57696
                                        if (i >= DUK__MAX_RE_DECESC_DIGITS) {
 
57697
                                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57698
                                                          "invalid regexp escape (decimal escape too long)");
 
57699
                                        }
 
57700
                                        DUK__ADVANCE(lex_ctx, 1);       /* eat backslash on entry */
 
57701
                                        x = DUK__L0();
 
57702
                                        if (!DUK__ISDIGIT(x)) {
 
57703
                                                break;
 
57704
                                        }
 
57705
                                        val = val * 10 + duk__hexval(lex_ctx, x);
 
57706
                                }
 
57707
                                /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
 
57708
                                advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
 
57709
                                out_token->num = val;
 
57710
                        }
 
57711
                } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
 
57712
                           y == DUK_UNICODE_CP_ZWNJ ||
 
57713
                           y == DUK_UNICODE_CP_ZWJ ||
 
57714
                           y == '$') {
 
57715
                        /* IdentityEscape, with dollar added as a valid additional
 
57716
                         * non-standard escape (see test-regexp-identity-escape-dollar.js).
 
57717
                         * Careful not to match end-of-buffer (<0) here.
 
57718
                         */
 
57719
                        out_token->num = y;
 
57720
                } else {
 
57721
                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57722
                                  "invalid regexp escape");
 
57723
                }
 
57724
                break;
 
57725
        }
 
57726
        case '(': {
 
57727
                /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
 
57728
 
 
57729
                if (y == '?') {
 
57730
                        if (DUK__L2() == '=') {
 
57731
                                /* (?= */
 
57732
                                advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
 
57733
                        } else if (DUK__L2() == '!') {
 
57734
                                /* (?! */
 
57735
                                advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
 
57736
                        } else if (DUK__L2() == ':') {
 
57737
                                /* (?: */
 
57738
                                advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
 
57739
                        }
 
57740
                } else {
 
57741
                        /* ( */
 
57742
                        advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
 
57743
                }
 
57744
                break;
 
57745
        }
 
57746
        case ')': {
 
57747
                advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
 
57748
                break;
 
57749
        }
 
57750
        case '[': {
 
57751
                /*
 
57752
                 *  To avoid creating a heavy intermediate value for the list of ranges,
 
57753
                 *  only the start token ('[' or '[^') is parsed here.  The regexp
 
57754
                 *  compiler parses the ranges itself.
 
57755
                 */
 
57756
                advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
 
57757
                if (y == '^') {
 
57758
                        advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
 
57759
                }
 
57760
                break;
 
57761
        }
 
57762
        case ']':
 
57763
        case '}': {
 
57764
                /* Although these could be parsed as PatternCharacters unambiguously (here),
 
57765
                 * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
 
57766
                 */
 
57767
                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57768
                          "invalid regexp character");
 
57769
                break;
 
57770
        }
 
57771
        case -1: {
 
57772
                /* EOF */
 
57773
                advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
 
57774
                break;
 
57775
        }
 
57776
        default: {
 
57777
                /* PatternCharacter, all excluded characters are matched by cases above */
 
57778
                advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
 
57779
                out_token->num = x;
 
57780
                break;
 
57781
        }
 
57782
        }
 
57783
 
 
57784
        /*
 
57785
         *  Shared exit path
 
57786
         */
 
57787
 
 
57788
        DUK__ADVANCE(lex_ctx, advtok >> 8);
 
57789
        out_token->t = advtok & 0xff;
 
57790
}
 
57791
 
 
57792
/*
 
57793
 *  Special parser for character classes; calls callback for every
 
57794
 *  range parsed and returns the number of ranges present.
 
57795
 */
 
57796
 
 
57797
/* FIXME: this duplicates functionality in duk_regexp.c where a similar loop is
 
57798
 * required anyway.  We could use that BUT we need to update the regexp compiler
 
57799
 * 'nranges' too.  Work this out a bit more cleanly to save space.
 
57800
 */
 
57801
 
 
57802
/* FIXME: the handling of character range detection is a bit convoluted.
 
57803
 * Try to simplify and make smaller.
 
57804
 */
 
57805
 
 
57806
/* FIXME: logic for handling character ranges is now incorrect, it will accept
 
57807
 * e.g. [\d-z] whereas it should croak from it?  SMJS accepts this too, though.
 
57808
 *
 
57809
 * Needs a read through and a lot of additional tests.
 
57810
 */
 
57811
 
 
57812
static void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
 
57813
                                        duk_re_range_callback gen_range,
 
57814
                                        void *userdata,
 
57815
                                        duk_uint16_t *ranges,
 
57816
                                        int num) {
 
57817
        duk_uint16_t *ranges_end;
 
57818
 
 
57819
        DUK_UNREF(lex_ctx);
 
57820
 
 
57821
        ranges_end = ranges + num;
 
57822
        while (ranges < ranges_end) {
 
57823
                /* mark range 'direct', bypass canonicalization (see Wiki) */
 
57824
                gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
 
57825
                ranges += 2;
 
57826
        }
 
57827
}
 
57828
 
 
57829
void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
 
57830
        duk_int32_t start = -1;
 
57831
        int dash = 0;
 
57832
        duk_int32_t ch;
 
57833
 
 
57834
        DUK_DDPRINT("parsing regexp ranges");
 
57835
 
 
57836
        for (;;) {
 
57837
                int x;
 
57838
 
 
57839
                x = DUK__L0();
 
57840
                DUK__ADVANCE(lex_ctx, 1);
 
57841
 
 
57842
                ch = -1;  /* not strictly necessary, but avoids "uninitialized variable" warnings */
 
57843
                DUK_UNREF(ch);
 
57844
 
 
57845
                if (x < 0) {
 
57846
                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57847
                                  "eof while parsing character class");
 
57848
                } else if (x == ']') {
 
57849
                        DUK_ASSERT(!dash);      /* lookup should prevent this */
 
57850
                        if (start >= 0) {
 
57851
                                gen_range(userdata, (duk_codepoint_t) start, (duk_codepoint_t) start, 0);
 
57852
                        }
 
57853
                        break;
 
57854
                } else if (x == '-') {
 
57855
                        if (start >= 0 && !dash && DUK__L0() != ']') {
 
57856
                                /* '-' as a range indicator */
 
57857
                                dash = 1;
 
57858
                                continue;
 
57859
                        } else {
 
57860
                                /* '-' verbatim */
 
57861
                                ch = x;
 
57862
                        }
 
57863
                } else if (x == '\\') {
 
57864
                        /*
 
57865
                         *  The escapes are same as outside a character class, except that \b has a
 
57866
                         *  different meaning, and \B and backreferences are prohibited (see E5
 
57867
                         *  Section 15.10.2.19).  However, it's difficult to share code because we
 
57868
                         *  handle e.g. "\n" very differently: here we generate a single character
 
57869
                         *  range for it.
 
57870
                         */
 
57871
 
 
57872
                        x = DUK__L0();
 
57873
                        DUK__ADVANCE(lex_ctx, 1);
 
57874
 
 
57875
                        if (x == 'b') {
 
57876
                                /* Note: '\b' in char class is different than outside (assertion),
 
57877
                                 * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
 
57878
                                 * check below.
 
57879
                                 */
 
57880
                                ch = 0x0008;
 
57881
                        } else if (x == 'f') {
 
57882
                                ch = 0x000c;
 
57883
                        } else if (x == 'n') {
 
57884
                                ch = 0x000a;
 
57885
                        } else if (x == 't') {
 
57886
                                ch = 0x0009;
 
57887
                        } else if (x == 'r') {
 
57888
                                ch = 0x000d;
 
57889
                        } else if (x == 'v') {
 
57890
                                ch = 0x000b;
 
57891
                        } else if (x == 'c') {
 
57892
                                x = DUK__L0();
 
57893
                                DUK__ADVANCE(lex_ctx, 1);
 
57894
                                if ((x >= 'a' && x <= 'z') ||
 
57895
                                    (x >= 'A' && x <= 'Z')) {
 
57896
                                        ch = (x % 32);
 
57897
                                } else {
 
57898
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57899
                                                  "invalid regexp control escape");
 
57900
                                        return;  /* never reached, but avoids warnings of
 
57901
                                                  * potentially unused variables.
 
57902
                                                  */
 
57903
                                }
 
57904
                        } else if (x == 'x') {
 
57905
                                ch = duk__decode_hexesc_from_window(lex_ctx, 0);
 
57906
                                DUK__ADVANCE(lex_ctx, 2);
 
57907
                        } else if (x == 'u') {
 
57908
                                ch = duk__decode_uniesc_from_window(lex_ctx, 0);
 
57909
                                DUK__ADVANCE(lex_ctx, 4);
 
57910
                        } else if (x == 'd') {
 
57911
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57912
                                                            gen_range,
 
57913
                                                            userdata,
 
57914
                                                            duk_unicode_re_ranges_digit,
 
57915
                                                            sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
 
57916
                                ch = -1;
 
57917
                        } else if (x == 'D') {
 
57918
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57919
                                                            gen_range,
 
57920
                                                            userdata,
 
57921
                                                            duk_unicode_re_ranges_not_digit,
 
57922
                                                            sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
 
57923
                                ch = -1;
 
57924
                        } else if (x == 's') {
 
57925
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57926
                                                            gen_range,
 
57927
                                                            userdata,
 
57928
                                                            duk_unicode_re_ranges_white,
 
57929
                                                            sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
 
57930
                                ch = -1;
 
57931
                        } else if (x == 'S') {
 
57932
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57933
                                                            gen_range,
 
57934
                                                            userdata,
 
57935
                                                            duk_unicode_re_ranges_not_white,
 
57936
                                                            sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
 
57937
                                ch = -1;
 
57938
                        } else if (x == 'w') {
 
57939
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57940
                                                            gen_range,
 
57941
                                                            userdata,
 
57942
                                                            duk_unicode_re_ranges_wordchar,
 
57943
                                                            sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
 
57944
                                ch = -1;
 
57945
                        } else if (x == 'W') {
 
57946
                                duk__emit_u16_direct_ranges(lex_ctx,
 
57947
                                                            gen_range,
 
57948
                                                            userdata,
 
57949
                                                            duk_unicode_re_ranges_not_wordchar,
 
57950
                                                            sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
 
57951
                                ch = -1;
 
57952
                        } else if (DUK__ISDIGIT(x)) {
 
57953
                                /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
 
57954
                                if (x == 0 && !DUK__ISDIGIT(DUK__L0())) {
 
57955
                                        ch = 0x0000;
 
57956
                                } else {
 
57957
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57958
                                                  "invalid decimal escape");
 
57959
                                }
 
57960
                        } else if (!duk_unicode_is_identifier_part(x)) {
 
57961
                                /* IdentityEscape */
 
57962
                                ch = x;
 
57963
                        } else {
 
57964
                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57965
                                          "invalid regexp escape");
 
57966
                        }
 
57967
                } else {
 
57968
                        /* character represents itself */
 
57969
                        ch = x;
 
57970
                }
 
57971
 
 
57972
                /* ch is a literal character here or -1 if parsed entity was
 
57973
                 * an escape such as "\s".
 
57974
                 */
 
57975
 
 
57976
                if (ch < 0) {
 
57977
                        /* multi-character sets not allowed as part of ranges, see
 
57978
                         * E5 Section 15.10.2.15, abstract operation CharacterRange.
 
57979
                         */
 
57980
                        if (start >= 0) {
 
57981
                                if (dash) {
 
57982
                                        DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57983
                                                  "invalid range");
 
57984
                                } else {
 
57985
                                        gen_range(userdata, (duk_codepoint_t) start, (duk_codepoint_t) start, 0);
 
57986
                                        start = -1;
 
57987
                                        /* dash is already 0 */
 
57988
                                }
 
57989
                        }
 
57990
                } else {
 
57991
                        if (start >= 0) {
 
57992
                                if (dash) {
 
57993
                                        if (start > ch) {
 
57994
                                                DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
57995
                                                          "invalid range");
 
57996
                                        }
 
57997
                                        gen_range(userdata, (duk_codepoint_t) start, (duk_codepoint_t) ch, 0);
 
57998
                                        start = -1;
 
57999
                                        dash = 0;
 
58000
                                } else {
 
58001
                                        gen_range(userdata, (duk_codepoint_t) start, (duk_codepoint_t) start, 0);
 
58002
                                        start = ch;
 
58003
                                        /* dash is already 0 */
 
58004
                                }
 
58005
                        } else {
 
58006
                                start = ch;
 
58007
                        }
 
58008
                }
 
58009
        }
 
58010
 
 
58011
        return;
 
58012
}
 
58013
 
 
58014
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
58015
 
 
58016
#line 1 "duk_numconv.c"
 
58017
/*
 
58018
 *  Number-to-string and string-to-number conversions.
 
58019
 *
 
58020
 *  Slow path number-to-string and string-to-number conversion is based on
 
58021
 *  a Dragon4 variant, with fast paths for small integers.  Big integer
 
58022
 *  arithmetic is needed for guaranteeing that the conversion is correct
 
58023
 *  and uses a minimum number of digits.  The big number arithmetic has a
 
58024
 *  fixed maximum size and does not require dynamic allocations.
 
58025
 *
 
58026
 *  See: doc/number-conversion.txt.
 
58027
 */
 
58028
 
 
58029
/* include removed: duk_internal.h */
 
58030
 
 
58031
#define DUK__IEEE_DOUBLE_EXP_BIAS  1023
 
58032
#define DUK__IEEE_DOUBLE_EXP_MIN   (-1022)   /* biased exp == 0 -> denormal, exp -1022 */
 
58033
 
 
58034
#define DUK__DIGITCHAR(x)  duk_lc_digits[(x)]
 
58035
 
 
58036
/*
 
58037
 *  Tables generated with src/gennumdigits.py.
 
58038
 *
 
58039
 *  duk__str2num_digits_for_radix indicates, for each radix, how many input
 
58040
 *  digits should be considered significant for string-to-number conversion.
 
58041
 *  The input is also padded to this many digits to give the Dragon4
 
58042
 *  conversion enough (apparent) precision to work with.
 
58043
 *
 
58044
 *  duk__str2num_exp_limits indicates, for each radix, the radix-specific
 
58045
 *  minimum/maximum exponent values (for a Dragon4 integer mantissa)
 
58046
 *  below and above which the number is guaranteed to underflow to zero
 
58047
 *  or overflow to Infinity.  This allows parsing to keep bigint values
 
58048
 *  bounded.
 
58049
 */
 
58050
 
 
58051
static const duk_uint8_t duk__str2num_digits_for_radix[] = {
 
58052
        69, 44, 35, 30, 27, 25, 23, 22, 20, 20,    /* 2 to 11 */
 
58053
        20, 19, 19, 18, 18, 17, 17, 17, 16, 16,    /* 12 to 21 */
 
58054
        16, 16, 16, 15, 15, 15, 15, 15, 15, 14,    /* 22 to 31 */
 
58055
        14, 14, 14, 14, 14                         /* 31 to 36 */
 
58056
};
 
58057
 
 
58058
typedef struct {
 
58059
        duk_int16_t upper;
 
58060
        duk_int16_t lower;
 
58061
} duk__exp_limits;
 
58062
 
 
58063
static const duk__exp_limits duk__str2num_exp_limits[] = {
 
58064
        { 957, -1147 }, { 605, -725 },  { 479, -575 },  { 414, -496 },
 
58065
        { 372, -446 },  { 342, -411 },  { 321, -384 },  { 304, -364 },
 
58066
        { 291, -346 },  { 279, -334 },  { 268, -323 },  { 260, -312 },
 
58067
        { 252, -304 },  { 247, -296 },  { 240, -289 },  { 236, -283 },
 
58068
        { 231, -278 },  { 227, -273 },  { 223, -267 },  { 220, -263 },
 
58069
        { 216, -260 },  { 213, -256 },  { 210, -253 },  { 208, -249 },
 
58070
        { 205, -246 },  { 203, -244 },  { 201, -241 },  { 198, -239 },
 
58071
        { 196, -237 },  { 195, -234 },  { 193, -232 },  { 191, -230 },
 
58072
        { 190, -228 },  { 188, -226 },  { 187, -225 },
 
58073
};
 
58074
 
 
58075
/*
 
58076
 *  Limited functionality bigint implementation.
 
58077
 *
 
58078
 *  Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
 
58079
 *  with the caller responsible for ensuring this is never exceeded.  No memory
 
58080
 *  allocation (except stack) is needed for bigint computation.  Operations
 
58081
 *  have been tailored for number conversion needs.
 
58082
 *
 
58083
 *  Argument order is "assignment order", i.e. target first, then arguments:
 
58084
 *  x <- y * z  -->  duk__bi_mul(x, y, z);
 
58085
 */
 
58086
 
 
58087
/* This upper value has been experimentally determined; debug build will check
 
58088
 * bigint size with assertions.
 
58089
 */
 
58090
#define DUK__BI_MAX_PARTS  37  /* 37x32 = 1184 bits */
 
58091
 
 
58092
#ifdef DUK_USE_DDDEBUG
 
58093
#define DUK__BI_PRINT(name,x)  duk__bi_print((name),(x))
 
58094
#else
 
58095
#define DUK__BI_PRINT(name,x)
 
58096
#endif
 
58097
 
 
58098
/* Current size is about 152 bytes. */
 
58099
typedef struct {
 
58100
        duk_small_int_t n;
 
58101
        duk_uint32_t v[DUK__BI_MAX_PARTS];  /* low to high */
 
58102
} duk__bigint;
 
58103
 
 
58104
#ifdef DUK_USE_DDDEBUG
 
58105
static void duk__bi_print(const char *name, duk__bigint *x) {
 
58106
        /* Overestimate required size; debug code so not critical to be tight. */
 
58107
        char buf[DUK__BI_MAX_PARTS * 9 + 64];
 
58108
        char *p = buf;
 
58109
        duk_small_int_t i;
 
58110
 
 
58111
        /* No NUL term checks in this debug code. */
 
58112
        p += DUK_SPRINTF(p, "%p n=%d", (void *) x, x->n);
 
58113
        if (x->n == 0) {
 
58114
                p += DUK_SPRINTF(p, " 0");
 
58115
        }
 
58116
        for (i = x->n - 1; i >= 0; i--) {
 
58117
                p += DUK_SPRINTF(p, " %08x", (unsigned int) x->v[i]);
 
58118
        }
 
58119
 
 
58120
        DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf);
 
58121
}
 
58122
#endif
 
58123
 
 
58124
#ifdef DUK_USE_ASSERTIONS
 
58125
static duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
 
58126
        return (duk_small_int_t) 
 
58127
               ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
 
58128
                 ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
 
58129
}
 
58130
#endif
 
58131
 
 
58132
static void duk__bi_normalize(duk__bigint *x) {
 
58133
        duk_small_int_t i;
 
58134
 
 
58135
        for (i = x->n - 1; i >= 0; i--) {
 
58136
                if (x->v[i] != 0) {
 
58137
                        break;
 
58138
                }
 
58139
        }
 
58140
 
 
58141
        /* Note: if 'x' is zero, x->n becomes 0 here */
 
58142
        x->n = i + 1;
 
58143
        DUK_ASSERT(duk__bi_is_valid(x));
 
58144
}
 
58145
 
 
58146
/* x <- y */
 
58147
static void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
 
58148
        duk_small_int_t n;
 
58149
 
 
58150
        n = y->n;
 
58151
        x->n = n;
 
58152
        if (n == 0) {
 
58153
                return;
 
58154
        }
 
58155
        DUK_MEMCPY((void *) x->v, (void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
 
58156
}
 
58157
 
 
58158
static void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
 
58159
        if (v == 0U) {
 
58160
                x->n = 0;
 
58161
        } else {
 
58162
                x->n = 1;
 
58163
                x->v[0] = v;
 
58164
        }
 
58165
        DUK_ASSERT(duk__bi_is_valid(x));
 
58166
}
 
58167
 
 
58168
/* Return value: <0  <=>  x < y
 
58169
 *                0  <=>  x == y
 
58170
 *               >0  <=>  x > y
 
58171
 */
 
58172
static int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
 
58173
        duk_small_int_t i, nx, ny;
 
58174
        duk_uint32_t tx, ty;
 
58175
 
 
58176
        DUK_ASSERT(duk__bi_is_valid(x));
 
58177
        DUK_ASSERT(duk__bi_is_valid(y));
 
58178
 
 
58179
        nx = x->n;
 
58180
        ny = y->n;
 
58181
        if (nx > ny) {
 
58182
                goto ret_gt;
 
58183
        }
 
58184
        if (nx < ny) {
 
58185
                goto ret_lt;
 
58186
        }
 
58187
        for (i = nx - 1; i >= 0; i--) {
 
58188
                tx = x->v[i];
 
58189
                ty = y->v[i];
 
58190
 
 
58191
                if (tx > ty) {
 
58192
                        goto ret_gt;
 
58193
                }
 
58194
                if (tx < ty) {
 
58195
                        goto ret_lt;
 
58196
                }
 
58197
        }
 
58198
 
 
58199
        return 0;
 
58200
 
 
58201
 ret_gt:
 
58202
        return 1;
 
58203
 
 
58204
 ret_lt:
 
58205
        return -1;
 
58206
}
 
58207
 
 
58208
/* x <- y + z */
 
58209
#ifdef DUK_USE_64BIT_OPS
 
58210
static void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
 
58211
        duk_uint64_t tmp;
 
58212
        duk_small_int_t i, ny, nz;
 
58213
 
 
58214
        DUK_ASSERT(duk__bi_is_valid(y));
 
58215
        DUK_ASSERT(duk__bi_is_valid(z));
 
58216
 
 
58217
        if (z->n > y->n) {
 
58218
                duk__bigint *t;
 
58219
                t = y; y = z; z = t;
 
58220
        }
 
58221
        DUK_ASSERT(y->n >= z->n);
 
58222
 
 
58223
        ny = y->n; nz = z->n;
 
58224
        tmp = 0U;
 
58225
        for (i = 0; i < ny; i++) {
 
58226
                DUK_ASSERT(i < DUK__BI_MAX_PARTS);
 
58227
                tmp += y->v[i];
 
58228
                if (i < nz) {
 
58229
                        tmp += z->v[i];
 
58230
                }
 
58231
                x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
 
58232
                tmp = tmp >> 32;
 
58233
        }
 
58234
        if (tmp != 0U) {
 
58235
                DUK_ASSERT(i < DUK__BI_MAX_PARTS);
 
58236
                x->v[i++] = (duk_uint32_t) tmp;
 
58237
        }
 
58238
        x->n = i;
 
58239
        DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
 
58240
 
 
58241
        /* no need to normalize */
 
58242
        DUK_ASSERT(duk__bi_is_valid(x));
 
58243
}
 
58244
#else  /* DUK_USE_64BIT_OPS */
 
58245
static void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
 
58246
        duk_uint32_t carry, tmp1, tmp2;
 
58247
        duk_small_int_t i, ny, nz;
 
58248
 
 
58249
        DUK_ASSERT(duk__bi_is_valid(y));
 
58250
        DUK_ASSERT(duk__bi_is_valid(z));
 
58251
 
 
58252
        if (z->n > y->n) {
 
58253
                duk__bigint *t;
 
58254
                t = y; y = z; z = t;
 
58255
        }
 
58256
        DUK_ASSERT(y->n >= z->n);
 
58257
 
 
58258
        ny = y->n; nz = z->n;
 
58259
        carry = 0U;
 
58260
        for (i = 0; i < ny; i++) {
 
58261
                /* Carry is detected based on wrapping which relies on exact 32-bit
 
58262
                 * types.
 
58263
                 */
 
58264
                DUK_ASSERT(i < DUK__BI_MAX_PARTS);
 
58265
                tmp1 = y->v[i];
 
58266
                tmp2 = tmp1;
 
58267
                if (i < nz) {
 
58268
                        tmp2 += z->v[i];
 
58269
                }
 
58270
 
 
58271
                /* Careful with carry condition:
 
58272
                 *  - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
 
58273
                 *  - If carry added:     0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
 
58274
                 */
 
58275
                if (carry) {
 
58276
                        tmp2++;
 
58277
                        carry = (tmp2 <= tmp1 ? 1U : 0U);
 
58278
                } else {
 
58279
                        carry = (tmp2 < tmp1 ? 1U : 0U);
 
58280
                }
 
58281
 
 
58282
                x->v[i] = tmp2;
 
58283
        }
 
58284
        if (carry) {
 
58285
                DUK_ASSERT(i < DUK__BI_MAX_PARTS);
 
58286
                DUK_ASSERT(carry == 1U);
 
58287
                x->v[i++] = carry;
 
58288
        }
 
58289
        x->n = i;
 
58290
        DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
 
58291
 
 
58292
        /* no need to normalize */
 
58293
        DUK_ASSERT(duk__bi_is_valid(x));
 
58294
}
 
58295
#endif  /* DUK_USE_64BIT_OPS */
 
58296
 
 
58297
/* x <- y + z */
 
58298
static void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
 
58299
        duk__bigint tmp;
 
58300
 
 
58301
        DUK_ASSERT(duk__bi_is_valid(y));
 
58302
 
 
58303
        /* XXX: this could be optimized; there is only one call site now though */
 
58304
        duk__bi_set_small(&tmp, z);
 
58305
        duk__bi_add(x, y, &tmp);
 
58306
 
 
58307
        DUK_ASSERT(duk__bi_is_valid(x));
 
58308
}
 
58309
 
 
58310
#if 0  /* unused */
 
58311
/* x <- x + y, use t as temp */
 
58312
static void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
 
58313
        duk__bi_add(t, x, y);
 
58314
        duk__bi_copy(x, t);
 
58315
}
 
58316
#endif
 
58317
 
 
58318
/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
 
58319
#ifdef DUK_USE_64BIT_OPS
 
58320
static void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
 
58321
        duk_small_int_t i, ny, nz;
 
58322
        duk_uint32_t ty, tz;
 
58323
        duk_int64_t tmp;
 
58324
 
 
58325
        DUK_ASSERT(duk__bi_is_valid(y));
 
58326
        DUK_ASSERT(duk__bi_is_valid(z));
 
58327
        DUK_ASSERT(duk__bi_compare(y, z) >= 0);
 
58328
        DUK_ASSERT(y->n >= z->n);
 
58329
 
 
58330
        ny = y->n; nz = z->n;
 
58331
        tmp = 0;
 
58332
        for (i = 0; i < ny; i++) {
 
58333
                ty = y->v[i];
 
58334
                if (i < nz) {
 
58335
                        tz = z->v[i];
 
58336
                } else {
 
58337
                        tz = 0;
 
58338
                }
 
58339
                tmp = (int64_t) ty - (int64_t) tz + tmp;
 
58340
                x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
 
58341
                tmp = tmp >> 32;  /* 0 or -1 */
 
58342
        }
 
58343
        DUK_ASSERT(tmp == 0);
 
58344
 
 
58345
        x->n = i;
 
58346
        duk__bi_normalize(x);  /* need to normalize, may even cancel to 0 */
 
58347
        DUK_ASSERT(duk__bi_is_valid(x));
 
58348
}
 
58349
#else
 
58350
static void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
 
58351
        duk_small_int_t i, ny, nz;
 
58352
        duk_uint32_t tmp1, tmp2, borrow;
 
58353
 
 
58354
        DUK_ASSERT(duk__bi_is_valid(y));
 
58355
        DUK_ASSERT(duk__bi_is_valid(z));
 
58356
        DUK_ASSERT(duk__bi_compare(y, z) >= 0);
 
58357
        DUK_ASSERT(y->n >= z->n);
 
58358
 
 
58359
        ny = y->n; nz = z->n;
 
58360
        borrow = 0U;
 
58361
        for (i = 0; i < ny; i++) {
 
58362
                /* Borrow is detected based on wrapping which relies on exact 32-bit
 
58363
                 * types.
 
58364
                 */
 
58365
                tmp1 = y->v[i];
 
58366
                tmp2 = tmp1;
 
58367
                if (i < nz) {
 
58368
                        tmp2 -= z->v[i];
 
58369
                }
 
58370
 
 
58371
                /* Careful with borrow condition:
 
58372
                 *  - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
 
58373
                 *  - If borrow subtracted:     0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
 
58374
                 */
 
58375
                if (borrow) {
 
58376
                        tmp2--;
 
58377
                        borrow = (tmp2 >= tmp1 ? 1U : 0U);
 
58378
                } else {
 
58379
                        borrow = (tmp2 > tmp1 ? 1U : 0U);
 
58380
                }
 
58381
 
 
58382
                x->v[i] = tmp2;
 
58383
        }
 
58384
        DUK_ASSERT(borrow == 0U);
 
58385
 
 
58386
        x->n = i;
 
58387
        duk__bi_normalize(x);  /* need to normalize, may even cancel to 0 */
 
58388
        DUK_ASSERT(duk__bi_is_valid(x));
 
58389
}
 
58390
#endif
 
58391
 
 
58392
#if 0  /* unused */
 
58393
/* x <- y - z */
 
58394
static void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
 
58395
        duk__bigint tmp;
 
58396
 
 
58397
        DUK_ASSERT(duk__bi_is_valid(y));
 
58398
 
 
58399
        /* XXX: this could be optimized */
 
58400
        duk__bi_set_small(&tmp, z);
 
58401
        duk__bi_sub(x, y, &tmp);
 
58402
 
 
58403
        DUK_ASSERT(duk__bi_is_valid(x));
 
58404
}
 
58405
#endif
 
58406
 
 
58407
/* x <- x - y, use t as temp */
 
58408
static void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
 
58409
        duk__bi_sub(t, x, y);
 
58410
        duk__bi_copy(x, t);
 
58411
}
 
58412
 
 
58413
/* x <- y * z */
 
58414
static void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
 
58415
        duk_small_int_t i, j, nx, nz;
 
58416
 
 
58417
        DUK_ASSERT(duk__bi_is_valid(y));
 
58418
        DUK_ASSERT(duk__bi_is_valid(z));
 
58419
 
 
58420
        nx = y->n + z->n;  /* max possible */
 
58421
        DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
 
58422
 
 
58423
        if (nx == 0) {
 
58424
                /* Both inputs are zero; cases where only one is zero can go
 
58425
                 * through main algorithm.
 
58426
                 */
 
58427
                x->n = 0;
 
58428
                return;
 
58429
        }
 
58430
 
 
58431
        DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
 
58432
        x->n = nx;
 
58433
 
 
58434
        nz = z->n;
 
58435
        for (i = 0; i < y->n; i++) {
 
58436
#ifdef DUK_USE_64BIT_OPS
 
58437
                duk_uint64_t tmp = 0U;
 
58438
                for (j = 0; j < nz; j++) {
 
58439
                        tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
 
58440
                        x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
 
58441
                        tmp = tmp >> 32;
 
58442
                }
 
58443
                if (tmp > 0) {
 
58444
                        DUK_ASSERT(i + j < nx);
 
58445
                        DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
 
58446
                        DUK_ASSERT(x->v[i+j] == 0U);
 
58447
                        x->v[i+j] = (duk_uint32_t) tmp;
 
58448
                }
 
58449
#else
 
58450
                /*
 
58451
                 *  Multiply + add + carry for 32-bit components using only 16x16->32
 
58452
                 *  multiplies and carry detection based on unsigned overflow.
 
58453
                 *
 
58454
                 *    1st mult, 32-bit: (A*2^16 + B)
 
58455
                 *    2nd mult, 32-bit: (C*2^16 + D)
 
58456
                 *    3rd add, 32-bit: E
 
58457
                 *    4th add, 32-bit: F
 
58458
                 *
 
58459
                 *      (AC*2^16 + B) * (C*2^16 + D) + E + F
 
58460
                 *    = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
 
58461
                 *    = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
 
58462
                 *    = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
 
58463
                 */
 
58464
                duk_uint32_t a, b, c, d, e, f;
 
58465
                duk_uint32_t r, s, t;
 
58466
 
 
58467
                a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
 
58468
 
 
58469
                f = 0;
 
58470
                for (j = 0; j < nz; j++) {
 
58471
                        c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
 
58472
                        e = x->v[i+j];
 
58473
 
 
58474
                        /* build result as: (r << 32) + s: start with (BD + E + F) */
 
58475
                        r = 0;
 
58476
                        s = b * d;
 
58477
 
 
58478
                        /* add E */
 
58479
                        t = s + e;
 
58480
                        if (t < s) { r++; }  /* carry */
 
58481
                        s = t;
 
58482
 
 
58483
                        /* add F */
 
58484
                        t = s + f;
 
58485
                        if (t < s) { r++; }  /* carry */
 
58486
                        s = t;
 
58487
 
 
58488
                        /* add BC*2^16 */
 
58489
                        t = b * c;
 
58490
                        r += (t >> 16);
 
58491
                        t = s + ((t & 0xffffUL) << 16);
 
58492
                        if (t < s) { r++; }  /* carry */
 
58493
                        s = t;
 
58494
 
 
58495
                        /* add AD*2^16 */
 
58496
                        t = a * d;
 
58497
                        r += (t >> 16);
 
58498
                        t = s + ((t & 0xffffUL) << 16);
 
58499
                        if (t < s) { r++; }  /* carry */
 
58500
                        s = t;
 
58501
 
 
58502
                        /* add AC*2^32 */
 
58503
                        t = a * c;
 
58504
                        r += t;
 
58505
 
 
58506
                        DUK_DDDPRINT("ab=%08x cd=%08x ef=%08x -> rs=%08x %08x",
 
58507
                                     (unsigned int) y->v[i], (unsigned int) z->v[j],
 
58508
                                     (unsigned int) x->v[i+j], (unsigned int) r,
 
58509
                                     (unsigned int) s);
 
58510
 
 
58511
                        x->v[i+j] = s;
 
58512
                        f = r;
 
58513
                }
 
58514
                if (f > 0U) {
 
58515
                        DUK_ASSERT(i + j < nx);
 
58516
                        DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
 
58517
                        DUK_ASSERT(x->v[i+j] == 0U);
 
58518
                        x->v[i+j] = (duk_uint32_t) f;
 
58519
                }
 
58520
#endif  /* DUK_USE_64BIT_OPS */
 
58521
        }
 
58522
 
 
58523
        duk__bi_normalize(x);
 
58524
        DUK_ASSERT(duk__bi_is_valid(x));
 
58525
}
 
58526
 
 
58527
/* x <- y * z */
 
58528
static void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
 
58529
        duk__bigint tmp;
 
58530
 
 
58531
        DUK_ASSERT(duk__bi_is_valid(y));
 
58532
 
 
58533
        /* XXX: this could be optimized */
 
58534
        duk__bi_set_small(&tmp, z);
 
58535
        duk__bi_mul(x, y, &tmp);
 
58536
 
 
58537
        DUK_ASSERT(duk__bi_is_valid(x));
 
58538
}
 
58539
 
 
58540
/* x <- x * y, use t as temp */
 
58541
static void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
 
58542
        duk__bi_mul(t, x, y);
 
58543
        duk__bi_copy(x, t);
 
58544
}
 
58545
 
 
58546
/* x <- x * y, use t as temp */
 
58547
static void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
 
58548
        duk__bi_mul_small(t, x, y);
 
58549
        duk__bi_copy(x, t);
 
58550
}
 
58551
 
 
58552
static int duk__bi_is_even(duk__bigint *x) {
 
58553
        DUK_ASSERT(duk__bi_is_valid(x));
 
58554
        return (x->n == 0) || ((x->v[0] & 0x01) == 0);
 
58555
}
 
58556
 
 
58557
static int duk__bi_is_zero(duk__bigint *x) {
 
58558
        DUK_ASSERT(duk__bi_is_valid(x));
 
58559
        return (x->n == 0);  /* this is the case for normalized numbers */
 
58560
}
 
58561
 
 
58562
/* Bigint is 2^52.  Used to detect normalized IEEE double mantissa values
 
58563
 * which are at the lowest edge (next floating point value downwards has
 
58564
 * a different exponent).  The lowest mantissa has the form:
 
58565
 *
 
58566
 *     1000........000    (52 zeroes; only "hidden bit" is set)
 
58567
 */
 
58568
static duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
 
58569
        DUK_ASSERT(duk__bi_is_valid(x));
 
58570
        return (duk_small_int_t)
 
58571
                (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
 
58572
}
 
58573
 
 
58574
/* x <- (1<<y) */
 
58575
static void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
 
58576
        duk_small_int_t n, r;
 
58577
 
 
58578
        n = (y / 32) + 1;
 
58579
        DUK_ASSERT(n > 0);
 
58580
        r = y % 32;
 
58581
        DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
 
58582
        x->n = n;
 
58583
        x->v[n - 1] = (((duk_uint32_t) 1) << r);
 
58584
}
 
58585
 
 
58586
/* x <- b^y; use t1 and t2 as temps */
 
58587
static void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_int_t y, duk__bigint *t1, duk__bigint *t2) {
 
58588
        /* Fast path the binary case */
 
58589
 
 
58590
        DUK_ASSERT(x != t1 && x != t2 && t1 != t2);  /* distinct bignums, easy mistake to make */
 
58591
        DUK_ASSERT(b >= 0);
 
58592
        DUK_ASSERT(y >= 0);
 
58593
 
 
58594
        if (b == 2) {
 
58595
                duk__bi_twoexp(x, y);
 
58596
                return;
 
58597
        }
 
58598
 
 
58599
        /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
 
58600
 
 
58601
        DUK_DDDPRINT("exp_small: b=%d, y=%d", (int) b, (int) y);
 
58602
 
 
58603
        duk__bi_set_small(x, 1);
 
58604
        duk__bi_set_small(t1, b);
 
58605
        for (;;) {
 
58606
                /* Loop structure ensures that we don't compute t1^2 unnecessarily
 
58607
                 * on the final round, as that might create a bignum exceeding the
 
58608
                 * current DUK__BI_MAX_PARTS limit.
 
58609
                 */
 
58610
                if (y & 0x01) {
 
58611
                        duk__bi_mul_copy(x, t1, t2);
 
58612
                }
 
58613
                y = y >> 1;
 
58614
                if (y == 0) {
 
58615
                        break;
 
58616
                }
 
58617
                duk__bi_mul_copy(t1, t1, t2);
 
58618
        }
 
58619
 
 
58620
        DUK__BI_PRINT("exp_small result", x);
 
58621
}
 
58622
 
 
58623
/*
 
58624
 *  A Dragon4 number-to-string variant, based on:
 
58625
 *
 
58626
 *    Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
 
58627
 *    Accurately"
 
58628
 *
 
58629
 *    Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
 
58630
 *    Quickly and Accurately"
 
58631
 *
 
58632
 *  The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
 
58633
 *  i.e. the base implementation without logarithm estimation speedups
 
58634
 *  (these would increase code footprint considerably).  Fixed-format output
 
58635
 *  does not follow the suggestions in the paper; instead, we generate an
 
58636
 *  extra digit and round-with-carry.
 
58637
 *
 
58638
 *  The same algorithm is used for number parsing (with b=10 and B=2)
 
58639
 *  by generating one extra digit and doing rounding manually.
 
58640
 *
 
58641
 *  See doc/number-conversion.txt for limitations.
 
58642
 */
 
58643
 
 
58644
/* Maximum number of digits generated. */
 
58645
#define DUK__MAX_OUTPUT_DIGITS          1040  /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
 
58646
 
 
58647
/* Maximum number of characters in formatted value. */
 
58648
#define DUK__MAX_FORMATTED_LENGTH       1040  /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
 
58649
 
 
58650
/* Number and (minimum) size of bigints in the nc_ctx structure. */
 
58651
#define DUK__NUMCONV_CTX_NUM_BIGINTS    7
 
58652
#define DUK__NUMCONV_CTX_BIGINTS_SIZE   (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
 
58653
 
 
58654
typedef struct {
 
58655
        /* Currently about 7*152 = 1064 bytes.  The space for these
 
58656
         * duk__bigints is used also as a temporary buffer for generating
 
58657
         * the final string.  This is a bit awkard; a union would be
 
58658
         * more correct.
 
58659
         */
 
58660
        duk__bigint f, r, s, mp, mm, t1, t2;
 
58661
 
 
58662
        duk_small_int_t is_s2n;        /* if 1, doing a string-to-number; else doing a number-to-string */
 
58663
        duk_small_int_t is_fixed;      /* if 1, doing a fixed format output (not free format) */
 
58664
        duk_small_int_t req_digits;    /* requested number of output digits; 0 = free-format */
 
58665
        duk_small_int_t abs_pos;       /* digit position is absolute, not relative */
 
58666
        duk_small_int_t e;             /* exponent for 'f' */
 
58667
        duk_small_int_t b;             /* input radix */
 
58668
        duk_small_int_t B;             /* output radix */
 
58669
        duk_small_int_t k;             /* see algorithm */
 
58670
        duk_small_int_t low_ok;        /* see algorithm */
 
58671
        duk_small_int_t high_ok;       /* see algorithm */
 
58672
        duk_small_int_t unequal_gaps;  /* m+ != m- (very rarely) */
 
58673
 
 
58674
        /* Buffer used for generated digits, values are in the range [0,B-1]. */
 
58675
        duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
 
58676
        duk_small_int_t count;  /* digit count */
 
58677
} duk__numconv_stringify_ctx;
 
58678
 
 
58679
/* Note: computes with 'idx' in assertions, so caller beware.
 
58680
 * 'idx' is preincremented, i.e. '1' on first call, because it
 
58681
 * is more convenient for the caller.
 
58682
 */
 
58683
#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x)  do { \
 
58684
                DUK_ASSERT((preinc_idx) - 1 >= 0); \
 
58685
                DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
 
58686
                ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
 
58687
        } while (0)
 
58688
 
 
58689
static duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
 
58690
        duk_uint8_t *p;
 
58691
        duk_size_t len;
 
58692
        duk_small_int_t dig;
 
58693
        duk_small_int_t t;
 
58694
 
 
58695
        DUK_ASSERT(radix >= 2 && radix <= 36);
 
58696
 
 
58697
        /* A 32-bit unsigned integer formats to at most 32 digits (the
 
58698
         * worst case happens with radix == 2).  Output the digits backwards,
 
58699
         * and use a memmove() to get them in the right place.
 
58700
         */
 
58701
 
 
58702
        p = buf + 32;
 
58703
        for (;;) {
 
58704
                t = x / radix;
 
58705
                dig = x - t * radix;
 
58706
                x = t;
 
58707
 
 
58708
                DUK_ASSERT(dig >= 0 && dig < 36);
 
58709
                *(--p) = DUK__DIGITCHAR(dig);
 
58710
 
 
58711
                if (x == 0) {
 
58712
                        break;
 
58713
                }
 
58714
        }
 
58715
        len = (size_t) ((buf + 32) - p);
 
58716
 
 
58717
        DUK_MEMMOVE((void *) buf, (void *) p, len);
 
58718
 
 
58719
        return len;
 
58720
}
 
58721
 
 
58722
static void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
 
58723
        duk_small_int_t lowest_mantissa;
 
58724
 
 
58725
#if 1
 
58726
        /* Assume IEEE round-to-even, so that shorter encoding can be used
 
58727
         * when round-to-even would produce correct result.  By removing
 
58728
         * this check (and having low_ok == high_ok == 0) the results would
 
58729
         * still be accurate but in some cases longer than necessary.
 
58730
         */
 
58731
        if (duk__bi_is_even(&nc_ctx->f)) {
 
58732
                DUK_DDDPRINT("f is even");
 
58733
                nc_ctx->low_ok = 1;
 
58734
                nc_ctx->high_ok = 1;
 
58735
        } else {
 
58736
                DUK_DDDPRINT("f is odd");
 
58737
                nc_ctx->low_ok = 0;
 
58738
                nc_ctx->high_ok = 0;
 
58739
        }
 
58740
#else
 
58741
        /* Note: not honoring round-to-even should work but now generates incorrect
 
58742
         * results.  For instance, 1e23 serializes to "a000...", i.e. the first digit
 
58743
         * equals the radix (10).  Scaling stops one step too early in this case.
 
58744
         * Don't know why this is the case, but since this code path is unused, it
 
58745
         * doesn't matter.
 
58746
         */
 
58747
        nc_ctx->low_ok = 0;
 
58748
        nc_ctx->high_ok = 0;
 
58749
#endif
 
58750
 
 
58751
        /* For string-to-number, pretend we never have the lowest mantissa as there
 
58752
         * is no natural "precision" for inputs.  Having lowest_mantissa == 0, we'll
 
58753
         * fall into the base cases for both e >= 0 and e < 0.
 
58754
         */
 
58755
        if (nc_ctx->is_s2n) {
 
58756
                lowest_mantissa = 0;
 
58757
        } else {
 
58758
                lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
 
58759
        }
 
58760
 
 
58761
        nc_ctx->unequal_gaps = 0;
 
58762
        if (nc_ctx->e >= 0) {
 
58763
                /* exponent non-negative (and thus not minimum exponent) */
 
58764
 
 
58765
                if (lowest_mantissa) {
 
58766
                        /* (>= e 0) AND (= f (expt b (- p 1)))
 
58767
                         *
 
58768
                         * be <- (expt b e) == b^e
 
58769
                         * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
 
58770
                         * r <- (* f be1 2) == 2 * f * b^(e+1)    [if b==2 -> f * b^(e+2)]
 
58771
                         * s <- (* b 2)                           [if b==2 -> 4]
 
58772
                         * m+ <- be1 == b^(e+1)
 
58773
                         * m- <- be == b^e
 
58774
                         * k <- 0
 
58775
                         * B <- B
 
58776
                         * low_ok <- round
 
58777
                         * high_ok <- round
 
58778
                         */
 
58779
 
 
58780
                        DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
 
58781
                                     "lowest mantissa value for this exponent -> "
 
58782
                                     "unequal gaps");
 
58783
 
 
58784
                        duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2);  /* mm <- b^e */
 
58785
                        duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b);  /* mp <- b^(e+1) */
 
58786
                        duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
 
58787
                        duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp);       /* r <- (2 * f) * b^(e+1) */
 
58788
                        duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2);            /* s <- 2 * b */
 
58789
                        nc_ctx->unequal_gaps = 1;
 
58790
                } else {
 
58791
                        /* (>= e 0) AND (not (= f (expt b (- p 1))))
 
58792
                         *
 
58793
                         * be <- (expt b e) == b^e
 
58794
                         * r <- (* f be 2) == 2 * f * b^e    [if b==2 -> f * b^(e+1)]
 
58795
                         * s <- 2
 
58796
                         * m+ <- be == b^e
 
58797
                         * m- <- be == b^e
 
58798
                         * k <- 0
 
58799
                         * B <- B
 
58800
                         * low_ok <- round
 
58801
                         * high_ok <- round
 
58802
                         */
 
58803
 
 
58804
                        DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
 
58805
                                     "not lowest mantissa for this exponent -> "
 
58806
                                     "equal gaps");
 
58807
 
 
58808
                        duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2);  /* mm <- b^e */
 
58809
                        duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm);                /* mp <- b^e */
 
58810
                        duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
 
58811
                        duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp);     /* r <- (2 * f) * b^e */
 
58812
                        duk__bi_set_small(&nc_ctx->s, 2);                      /* s <- 2 */
 
58813
                }
 
58814
        } else {
 
58815
                /* When doing string-to-number, lowest_mantissa is always 0 so
 
58816
                 * the exponent check, while incorrect, won't matter.
 
58817
                 */
 
58818
                if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
 
58819
                    lowest_mantissa /* lowest mantissa for this exponent*/) {
 
58820
                        /* r <- (* f b 2)                                [if b==2 -> (* f 4)]
 
58821
                         * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2    [if b==2 -> b^(2-e)]
 
58822
                         * m+ <- b == 2
 
58823
                         * m- <- 1
 
58824
                         * k <- 0
 
58825
                         * B <- B
 
58826
                         * low_ok <- round
 
58827
                         * high_ok <- round
 
58828
                         */
 
58829
 
 
58830
                        DUK_DDDPRINT("negative exponent; not minimum exponent and "
 
58831
                                     "lowest mantissa for this exponent -> "
 
58832
                                     "unequal gaps");
 
58833
 
 
58834
                        duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2);  /* r <- (2 * b) * f */
 
58835
                        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 */
 
58836
                        duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2);             /* s <- b^(1-e) * 2 */
 
58837
                        duk__bi_set_small(&nc_ctx->mp, 2);
 
58838
                        duk__bi_set_small(&nc_ctx->mm, 1);
 
58839
                        nc_ctx->unequal_gaps = 1;
 
58840
                } else {
 
58841
                        /* r <- (* f 2)
 
58842
                         * s <- (* (expt b (- e)) 2) == b^(-e) * 2    [if b==2 -> b^(1-e)]
 
58843
                         * m+ <- 1
 
58844
                         * m- <- 1
 
58845
                         * k <- 0
 
58846
                         * B <- B
 
58847
                         * low_ok <- round
 
58848
                         * high_ok <- round
 
58849
                         */
 
58850
 
 
58851
                        DUK_DDDPRINT("negative exponent; minimum exponent or not "
 
58852
                                     "lowest mantissa for this exponent -> "
 
58853
                                     "equal gaps");
 
58854
 
 
58855
                        duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2);            /* r <- 2 * f */
 
58856
                        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 */
 
58857
                        duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2);           /* s <- b^(-e) * 2 */
 
58858
                        duk__bi_set_small(&nc_ctx->mp, 1);
 
58859
                        duk__bi_set_small(&nc_ctx->mm, 1);
 
58860
                }
 
58861
        }
 
58862
}
 
58863
 
 
58864
static void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
 
58865
        duk_small_int_t k = 0;
 
58866
 
 
58867
        /* This is essentially the 'scale' algorithm, with recursion removed.
 
58868
         * Note that 'k' is either correct immediately, or will move in one
 
58869
         * direction in the loop.  There's no need to do the low/high checks
 
58870
         * on every round (like the Scheme algorithm does).
 
58871
         *
 
58872
         * The scheme algorithm finds 'k' and updates 's' simultaneously,
 
58873
         * while the logical algorithm finds 'k' with 's' having its initial
 
58874
         * value, after which 's' is updated separately (see the Burger-Dybvig
 
58875
         * paper, Section 3.1, steps 2 and 3).
 
58876
         *
 
58877
         * The case where m+ == m- (almost always) is optimized for, because
 
58878
         * it reduces the bigint operations considerably and almost always
 
58879
         * applies.  The scale loop only needs to work with m+, so this works.
 
58880
         */
 
58881
 
 
58882
        /* XXX: this algorithm could be optimized quite a lot by using e.g.
 
58883
         * a logarithm based estimator for 'k' and performing B^n multiplication
 
58884
         * using a lookup table or using some bit-representation based exp
 
58885
         * algorithm.  Currently we just loop, with significant performance
 
58886
         * impact for very large and very small numbers.
 
58887
         */
 
58888
 
 
58889
        DUK_DDDPRINT("scale: B=%d, low_ok=%d, high_ok=%d",
 
58890
                     (int) nc_ctx->B, (int) nc_ctx->low_ok, (int) nc_ctx->high_ok);
 
58891
        DUK__BI_PRINT("r(init)", &nc_ctx->r);
 
58892
        DUK__BI_PRINT("s(init)", &nc_ctx->s);
 
58893
        DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
 
58894
        DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
 
58895
 
 
58896
        for (;;) {
 
58897
                DUK_DDDPRINT("scale loop (inc k), k=%d", (int) k);
 
58898
                DUK__BI_PRINT("r", &nc_ctx->r);
 
58899
                DUK__BI_PRINT("s", &nc_ctx->s);
 
58900
                DUK__BI_PRINT("m+", &nc_ctx->mp);
 
58901
                DUK__BI_PRINT("m-", &nc_ctx->mm);
 
58902
 
 
58903
                duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 = (+ r m+) */
 
58904
                if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
 
58905
                        DUK_DDDPRINT("k is too low");
 
58906
                        /* r <- r
 
58907
                         * s <- (* s B)
 
58908
                         * m+ <- m+
 
58909
                         * m- <- m-
 
58910
                         * k <- (+ k 1)
 
58911
                         */
 
58912
 
 
58913
                        duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
 
58914
                        k++;
 
58915
                } else {
 
58916
                        break;
 
58917
                }
 
58918
        }
 
58919
 
 
58920
        /* k > 0 -> k was too low, and cannot be too high */
 
58921
        if (k > 0) {
 
58922
                goto skip_dec_k;
 
58923
        }
 
58924
 
 
58925
        for (;;) {
 
58926
                DUK_DDDPRINT("scale loop (dec k), k=%d", (int) k);
 
58927
                DUK__BI_PRINT("r", &nc_ctx->r);
 
58928
                DUK__BI_PRINT("s", &nc_ctx->s);
 
58929
                DUK__BI_PRINT("m+", &nc_ctx->mp);
 
58930
                DUK__BI_PRINT("m-", &nc_ctx->mm);
 
58931
 
 
58932
                duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 = (+ r m+) */
 
58933
                duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B);   /* t2 = (* (+ r m+) B) */
 
58934
                if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
 
58935
                        DUK_DDDPRINT("k is too high");
 
58936
                        /* r <- (* r B)
 
58937
                         * s <- s
 
58938
                         * m+ <- (* m+ B)
 
58939
                         * m- <- (* m- B)
 
58940
                         * k <- (- k 1)
 
58941
                         */
 
58942
                        duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
 
58943
                        duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
 
58944
                        if (nc_ctx->unequal_gaps) {
 
58945
                                DUK_DDDPRINT("m+ != m- -> need to update m- too");
 
58946
                                duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
 
58947
                        }
 
58948
                        k--;
 
58949
                } else {
 
58950
                        break;
 
58951
                }
 
58952
        }
 
58953
 
 
58954
 skip_dec_k:
 
58955
 
 
58956
        if (!nc_ctx->unequal_gaps) {
 
58957
                DUK_DDDPRINT("equal gaps, copy m- from m+");
 
58958
                duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp);  /* mm <- mp */
 
58959
        }
 
58960
        nc_ctx->k = k;
 
58961
 
 
58962
        DUK_DDDPRINT("final k: %d", (int) k);
 
58963
        DUK__BI_PRINT("r(final)", &nc_ctx->r);
 
58964
        DUK__BI_PRINT("s(final)", &nc_ctx->s);
 
58965
        DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
 
58966
        DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
 
58967
}
 
58968
 
 
58969
static void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
 
58970
        duk_small_int_t tc1, tc2;    /* terminating conditions */
 
58971
        duk_small_int_t d;           /* current digit */
 
58972
        duk_small_int_t count = 0;   /* digit count */
 
58973
 
 
58974
        /*
 
58975
         *  Digit generation loop.
 
58976
         *
 
58977
         *  Different termination conditions:
 
58978
         *
 
58979
         *    1. Free format output.  Terminate when shortest accurate
 
58980
         *       representation found.
 
58981
         *
 
58982
         *    2. Fixed format output, with specific number of digits.
 
58983
         *       Ignore termination conditions, terminate when digits
 
58984
         *       generated.  Caller requests an extra digit and rounds.
 
58985
         *
 
58986
         *    3. Fixed format output, with a specific absolute cut-off
 
58987
         *       position (e.g. 10 digits after decimal point).  Note
 
58988
         *       that we always generate at least one digit, even if
 
58989
         *       the digit is below the cut-off point already.
 
58990
         */
 
58991
 
 
58992
        for (;;) {
 
58993
                DUK_DDDPRINT("generate loop, count=%d, k=%d, B=%d, low_ok=%d, high_ok=%d",
 
58994
                             (int) count, (int) nc_ctx->k, (int) nc_ctx->B,
 
58995
                             (int) nc_ctx->low_ok, (int) nc_ctx->high_ok);
 
58996
                DUK__BI_PRINT("r", &nc_ctx->r);
 
58997
                DUK__BI_PRINT("s", &nc_ctx->s);
 
58998
                DUK__BI_PRINT("m+", &nc_ctx->mp);
 
58999
                DUK__BI_PRINT("m-", &nc_ctx->mm);
 
59000
 
 
59001
                /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
 
59002
                duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B);       /* t1 <- (* r B) */
 
59003
                d = 0;
 
59004
                for (;;) {
 
59005
                        if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
 
59006
                                break;
 
59007
                        }
 
59008
                        duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2);  /* t1 <- t1 - s */
 
59009
                        d++;
 
59010
                }
 
59011
                duk__bi_copy(&nc_ctx->r, &nc_ctx->t1);  /* r <- (remainder (* r B) s) */
 
59012
                                                        /* d <- (quotient (* r B) s)   (in range 0...B-1) */
 
59013
                DUK_DDDPRINT("-> d(quot)=%d", (int) d);
 
59014
                DUK__BI_PRINT("r(rem)", &nc_ctx->r);
 
59015
 
 
59016
                duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
 
59017
                duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
 
59018
                DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
 
59019
                DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
 
59020
 
 
59021
                /* Terminating conditions.  For fixed width output, we just ignore the
 
59022
                 * terminating conditions (and pretend that tc1 == tc2 == false).  The
 
59023
                 * the current shortcut for fixed-format output is to generate a few
 
59024
                 * extra digits and use rounding (with carry) to finish the output.
 
59025
                 */
 
59026
 
 
59027
                if (nc_ctx->is_fixed == 0) {
 
59028
                        /* free-form */
 
59029
                        tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
 
59030
 
 
59031
                        duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 <- (+ r m+) */
 
59032
                        tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (&nc_ctx->high_ok ? 0 : 1));
 
59033
 
 
59034
                        DUK_DDDPRINT("tc1=%d, tc2=%d", (int) tc1, (int) tc2);
 
59035
                } else {
 
59036
                        /* fixed-format */
 
59037
                        tc1 = 0;
 
59038
                        tc2 = 0;
 
59039
                }
 
59040
 
 
59041
                /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
 
59042
                 * on purpose, which is taken into account by the macro.
 
59043
                 */
 
59044
                count++;
 
59045
 
 
59046
                if (tc1) {
 
59047
                        if (tc2) {
 
59048
                                /* tc1 = true, tc2 = true */
 
59049
                                duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
 
59050
                                if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {  /* (< (* r 2) s) */
 
59051
                                        DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %d (k=%d)",
 
59052
                                                     (int) d, (int) nc_ctx->k);
 
59053
                                        DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
 
59054
                                } else {
 
59055
                                        DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %d (k=%d)",
 
59056
                                                     (int) (d + 1), (int) nc_ctx->k);
 
59057
                                        DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
 
59058
                                }
 
59059
                                break;
 
59060
                        } else {
 
59061
                                /* tc1 = true, tc2 = false */
 
59062
                                DUK_DDDPRINT("tc1=true, tc2=false: output d --> %d (k=%d)",
 
59063
                                             (int) d, (int) nc_ctx->k);
 
59064
                                DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
 
59065
                                break;
 
59066
                        }
 
59067
                } else {
 
59068
                        if (tc2) {
 
59069
                                /* tc1 = false, tc2 = true */
 
59070
                                DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %d (k=%d)",
 
59071
                                             (int) (d + 1), (int) nc_ctx->k);
 
59072
                                DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
 
59073
                                break;
 
59074
                        } else {
 
59075
                                /* tc1 = false, tc2 = false */
 
59076
                                DUK_DDDPRINT("tc1=false, tc2=false: output d --> %d (k=%d)",
 
59077
                                             (int) d, (int) nc_ctx->k);
 
59078
                                DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
 
59079
 
 
59080
                                /* r <- r    (updated above: r <- (remainder (* r B) s)
 
59081
                                 * s <- s
 
59082
                                 * m+ <- m+  (updated above: m+ <- (* m+ B)
 
59083
                                 * m- <- m-  (updated above: m- <- (* m- B)
 
59084
                                 * B, low_ok, high_ok are fixed
 
59085
                                 */
 
59086
 
 
59087
                                /* fall through and continue for-loop */
 
59088
                        }
 
59089
                }
 
59090
 
 
59091
                /* fixed-format termination conditions */
 
59092
                if (nc_ctx->is_fixed) {
 
59093
                        if (nc_ctx->abs_pos) {
 
59094
                                int pos = nc_ctx->k - count + 1;  /* count is already incremented, take into account */
 
59095
                                DUK_DDDPRINT("fixed format, absolute: abs pos=%d, k=%d, count=%d, req=%d",
 
59096
                                             (int) pos, (int) nc_ctx->k, (int) count, (int) nc_ctx->req_digits);
 
59097
                                if (pos <= nc_ctx->req_digits) {
 
59098
                                        DUK_DDDPRINT("digit position reached req_digits, end generate loop");
 
59099
                                        break;
 
59100
                                }
 
59101
                        } else {
 
59102
                                DUK_DDDPRINT("fixed format, relative: k=%d, count=%d, req=%d",
 
59103
                                             (int) nc_ctx->k, (int) count, (int) nc_ctx->req_digits);
 
59104
                                if (count >= nc_ctx->req_digits) {
 
59105
                                        DUK_DDDPRINT("digit count reached req_digits, end generate loop");
 
59106
                                        break;
 
59107
                                }
 
59108
                        }
 
59109
                }
 
59110
        }  /* for */
 
59111
 
 
59112
        nc_ctx->count = count;
 
59113
 
 
59114
        DUK_DDDPRINT("generate finished");
 
59115
 
 
59116
#ifdef DUK_USE_DDDEBUG
 
59117
        {
 
59118
                duk_uint8_t buf[2048];
 
59119
                duk_small_int_t i, t;
 
59120
                DUK_MEMZERO(buf, sizeof(buf));
 
59121
                for (i = 0; i < nc_ctx->count; i++) {
 
59122
                        t = nc_ctx->digits[i];
 
59123
                        if (t < 0 || t > 36) {
 
59124
                                buf[i] = (duk_uint8_t) '?';
 
59125
                        } else {
 
59126
                                buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
 
59127
                        }
 
59128
                }
 
59129
                DUK_DDDPRINT("-> generated digits; k=%d, digits='%s'",
 
59130
                             (int) nc_ctx->k, (const char *) buf);
 
59131
        }
 
59132
#endif
 
59133
}
 
59134
 
 
59135
/* Round up digits to a given position.  If position is out-of-bounds,
 
59136
 * does nothing.  If carry propagates over the first digit, a '1' is
 
59137
 * prepended to digits and 'k' will be updated.  Return value indicates
 
59138
 * whether carry propagated over the first digit.
 
59139
 *
 
59140
 * Note that nc_ctx->count is NOT updated based on the rounding position
 
59141
 * (it is updated only if carry overflows over the first digit and an
 
59142
 * extra digit is prepended).
 
59143
 */
 
59144
static duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
 
59145
        duk_small_int_t t;
 
59146
        duk_uint8_t *p;
 
59147
        duk_uint8_t roundup_limit;
 
59148
        duk_small_int_t ret = 0;
 
59149
 
 
59150
        /*
 
59151
         *  round_idx points to the digit which is considered for rounding; the
 
59152
         *  digit to its left is the final digit of the rounded value.  If round_idx
 
59153
         *  is zero, rounding will be performed; the result will either be an empty
 
59154
         *  rounded value or if carry happens a '1' digit is generated.
 
59155
         */
 
59156
 
 
59157
        if (round_idx >= nc_ctx->count) {
 
59158
                DUK_DDDPRINT("round_idx out of bounds (%d >= %d (count)) -> no rounding",
 
59159
                             (int) round_idx, (int) nc_ctx->count);
 
59160
                return 0;
 
59161
        } else if (round_idx < 0) {
 
59162
                DUK_DDDPRINT("round_idx out of bounds (%d < 0) -> no rounding",
 
59163
                             (int) round_idx);
 
59164
                return 0;
 
59165
        }
 
59166
 
 
59167
        /*
 
59168
         *  Round-up limit.
 
59169
         *
 
59170
         *  For even values, divides evenly, e.g. 10 -> roundup_limit=5.
 
59171
         *
 
59172
         *  For odd values, rounds up, e.g. 3 -> roundup_limit=2.
 
59173
         *  If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
 
59174
         */
 
59175
        roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
 
59176
 
 
59177
        p = &nc_ctx->digits[round_idx];
 
59178
        if (*p >= roundup_limit) {
 
59179
                DUK_DDDPRINT("fixed-format rounding carry required");
 
59180
                /* carry */
 
59181
                for (;;) {
 
59182
                        *p = 0;
 
59183
                        if (p == &nc_ctx->digits[0]) {
 
59184
                                DUK_DDDPRINT("carry propagated to first digit -> special case handling");
 
59185
                                DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
 
59186
                                            (void *) (&nc_ctx->digits[0]),
 
59187
                                            (size_t) (sizeof(char) * nc_ctx->count));
 
59188
                                nc_ctx->digits[0] = 1;  /* don't increase 'count' */
 
59189
                                nc_ctx->k++;  /* position of highest digit changed */
 
59190
                                nc_ctx->count++;  /* number of digits changed */
 
59191
                                ret = 1;
 
59192
                                break;
 
59193
                        }
 
59194
 
 
59195
                        DUK_DDDPRINT("fixed-format rounding carry: B=%d, roundup_limit=%d, p=%p, digits=%p",
 
59196
                                     (int) nc_ctx->B, (int) roundup_limit, (void *) p, (void *) nc_ctx->digits);
 
59197
                        p--;
 
59198
                        t = *p;
 
59199
                        DUK_DDDPRINT("digit before carry: %d", (int) t);
 
59200
                        if (++t < nc_ctx->B) {
 
59201
                                DUK_DDDPRINT("rounding carry terminated");
 
59202
                                *p = t;
 
59203
                                break;
 
59204
                        }
 
59205
 
 
59206
                        DUK_DDDPRINT("wraps, carry to next digit");
 
59207
                }
 
59208
        }
 
59209
 
 
59210
        return ret;
 
59211
}
 
59212
 
 
59213
#define DUK__NO_EXP  (65536)  /* arbitrary marker, outside valid exp range */
 
59214
 
 
59215
static void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
 
59216
                                          duk_context *ctx,
 
59217
                                          duk_small_int_t radix,
 
59218
                                          duk_small_int_t digits,
 
59219
                                          duk_small_uint_t flags,
 
59220
                                          duk_small_int_t neg) {
 
59221
        duk_small_int_t k;
 
59222
        duk_small_int_t pos, pos_end;
 
59223
        duk_small_int_t exp;
 
59224
        duk_small_int_t dig;
 
59225
        duk_uint8_t *q;
 
59226
        duk_uint8_t *buf;
 
59227
 
 
59228
        /*
 
59229
         *  The string conversion here incorporates all the necessary Ecmascript
 
59230
         *  semantics without attempting to be generic.  nc_ctx->digits contains
 
59231
         *  nc_ctx->count digits (>= 1), with the topmost digit's 'position'
 
59232
         *  indicated by nc_ctx->k as follows:
 
59233
         *
 
59234
         *    digits="123" count=3 k=0   -->   0.123
 
59235
         *    digits="123" count=3 k=1   -->   1.23
 
59236
         *    digits="123" count=3 k=5   -->   12300
 
59237
         *    digits="123" count=3 k=-1  -->   0.0123
 
59238
         *
 
59239
         *  Note that the identifier names used for format selection are different
 
59240
         *  in Burger-Dybvig paper and Ecmascript specification (quite confusingly
 
59241
         *  so, because e.g. 'k' has a totally different meaning in each).  See
 
59242
         *  documentation for discussion.
 
59243
         *
 
59244
         *  Ecmascript doesn't specify any specific behavior for format selection
 
59245
         *  (e.g. when to use exponent notation) for non-base-10 numbers.
 
59246
         *
 
59247
         *  The bigint space in the context is reused for string output, as there
 
59248
         *  is more than enough space for that (>1kB at the moment), and we avoid
 
59249
         *  allocating even more stack.
 
59250
         */
 
59251
 
 
59252
        DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
 
59253
        DUK_ASSERT(nc_ctx->count >= 1);
 
59254
 
 
59255
        k = nc_ctx->k;
 
59256
        buf = (duk_uint8_t *) &nc_ctx->f;  /* XXX: union would be more correct */
 
59257
        q = buf;
 
59258
 
 
59259
        /* Exponent handling: if exponent format is used, record exponent value and
 
59260
         * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
 
59261
         *
 
59262
         * toFixed() prevents exponent use; otherwise apply a set of criteria to
 
59263
         * match the other API calls (toString(), toPrecision, etc).
 
59264
         */
 
59265
 
 
59266
        exp = DUK__NO_EXP;
 
59267
        if (!nc_ctx->abs_pos /* toFixed() */) {
 
59268
                if ((flags & DUK_N2S_FLAG_FORCE_EXP) ||             /* exponential notation forced */
 
59269
                    ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) &&          /* fixed precision and zero padding would be required */
 
59270
                     (k - digits >= 1)) ||                          /* (e.g. k=3, digits=2 -> "12X") */
 
59271
                    ((k > 21 || k <= -6) && (radix == 10))) {       /* toString() conditions */
 
59272
                        DUK_DDDPRINT("use exponential notation: k=%d -> exp=%d", (int) k, (int) (k - 1));
 
59273
                        exp = k - 1;  /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
 
59274
                        k = 1;  /* generate mantissa with a single leading whole number digit */
 
59275
                }
 
59276
        }
 
59277
 
 
59278
        if (neg) {
 
59279
                *q++ = '-';
 
59280
        }
 
59281
 
 
59282
        /* Start position (inclusive) and end position (exclusive) */
 
59283
        pos = (k >= 1 ? k : 1);
 
59284
        if (nc_ctx->is_fixed) {
 
59285
                if (nc_ctx->abs_pos) {
 
59286
                        /* toFixed() */
 
59287
                        pos_end = -digits;
 
59288
                } else {
 
59289
                        pos_end = k - digits;
 
59290
                }
 
59291
        } else {
 
59292
                pos_end = k - nc_ctx->count;
 
59293
        }
 
59294
        if (pos_end > 0) {
 
59295
                pos_end = 0;
 
59296
        }
 
59297
 
 
59298
        DUK_DDDPRINT("exp=%d, k=%d, count=%d, pos=%d, pos_end=%d, is_fixed=%d, "
 
59299
                     "digits=%d, abs_pos=%d",
 
59300
                     (int) exp, (int) k, (int) nc_ctx->count, (int) pos, (int) pos_end,
 
59301
                     (int) nc_ctx->is_fixed, (int) digits, (int) nc_ctx->abs_pos);
 
59302
 
 
59303
        /* Digit generation */
 
59304
        while (pos > pos_end) {
 
59305
                DUK_DDDPRINT("digit generation: pos=%d, pos_end=%d",
 
59306
                             (int) pos, (int) pos_end);
 
59307
                if (pos == 0) {
 
59308
                        *q++ = (duk_uint8_t) '.';
 
59309
                }
 
59310
                if (pos > k) {
 
59311
                        *q++ = (duk_uint8_t) '0';
 
59312
                } else if (pos <= k - nc_ctx->count) {
 
59313
                        *q++ = (duk_uint8_t) '0';
 
59314
                } else {
 
59315
                        dig = nc_ctx->digits[k - pos];
 
59316
                        DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
 
59317
                        *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
 
59318
                } 
 
59319
 
 
59320
                pos--;
 
59321
        }
 
59322
        DUK_ASSERT(pos <= 1);
 
59323
 
 
59324
        /* Exponent */
 
59325
        if (exp != DUK__NO_EXP) {
 
59326
                /*
 
59327
                 *  Exponent notation for non-base-10 numbers isn't specified in Ecmascript
 
59328
                 *  specification, as it never explicitly turns up: non-decimal numbers can
 
59329
                 *  only be formatted with Number.prototype.toString([radix]) and for that,
 
59330
                 *  behavior is not explicitly specified.
 
59331
                 *
 
59332
                 *  Logical choices include formatting the exponent as decimal (e.g. binary
 
59333
                 *  100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
 
59334
                 *  The Dragon4 algorithm (in the original paper) prints the exponent value
 
59335
                 *  in the target radix B.  However, for radix values 15 and above, the
 
59336
                 *  exponent separator 'e' is no longer easily parseable.  Consider, for
 
59337
                 *  instance, the number "1.faecee+1c".
 
59338
                 */
 
59339
 
 
59340
                size_t len;
 
59341
                char exp_sign;
 
59342
 
 
59343
                *q++ = 'e';
 
59344
                if (exp >= 0) {
 
59345
                        exp_sign = '+';
 
59346
                } else {
 
59347
                        exp_sign = '-';
 
59348
                        exp = -exp;
 
59349
                }
 
59350
                *q++ = (duk_uint8_t) exp_sign;
 
59351
                len = duk__dragon4_format_uint32(q, (duk_uint32_t) exp, radix);
 
59352
                q += len;
 
59353
        }
 
59354
 
 
59355
        duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
 
59356
}
 
59357
 
 
59358
/*
 
59359
 *  Conversion helpers
 
59360
 */
 
59361
 
 
59362
static void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
 
59363
        duk_double_union u;
 
59364
        duk_uint32_t tmp;
 
59365
        duk_small_int_t exp;
 
59366
 
 
59367
        /*
 
59368
         *    seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
 
59369
         *       A        B        C        D        E        F        G        H
 
59370
         *
 
59371
         *    s       sign bit
 
59372
         *    eee...  exponent field
 
59373
         *    fff...  fraction
 
59374
         *
 
59375
         *    ieee value = 1.ffff... * 2^(e - 1023)  (normal)
 
59376
         *               = 0.ffff... * 2^(-1022)     (denormal)
 
59377
         *
 
59378
         *    algorithm v = f * b^e
 
59379
         */
 
59380
 
 
59381
        DUK_DBLUNION_SET_DOUBLE(&u, x);
 
59382
 
 
59383
        nc_ctx->f.n = 2;
 
59384
 
 
59385
        tmp = DUK_DBLUNION_GET_LOW32(&u);
 
59386
        nc_ctx->f.v[0] = tmp;
 
59387
        tmp = DUK_DBLUNION_GET_HIGH32(&u);
 
59388
        nc_ctx->f.v[1] = tmp & 0x000fffffUL;
 
59389
        exp = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
 
59390
 
 
59391
        if (exp == 0) {
 
59392
                /* denormal */
 
59393
                exp = DUK__IEEE_DOUBLE_EXP_MIN - 52;
 
59394
                duk__bi_normalize(&nc_ctx->f);
 
59395
        } else {
 
59396
                /* normal: implicit leading 1-bit */
 
59397
                nc_ctx->f.v[1] |= 0x00100000UL;
 
59398
                exp = exp - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
 
59399
                DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));  /* true, because v[1] has at least one bit set */
 
59400
        }
 
59401
 
 
59402
        DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
 
59403
 
 
59404
        nc_ctx->e = exp;
 
59405
}
 
59406
 
 
59407
void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
 
59408
        duk_double_union u;
 
59409
        duk_small_int_t exp;
 
59410
        duk_small_int_t i;
 
59411
        duk_small_int_t bitstart;
 
59412
        duk_small_int_t bitround;
 
59413
        duk_small_int_t bitidx;
 
59414
        duk_small_int_t skip_round;
 
59415
        duk_uint32_t t, v;
 
59416
 
 
59417
        DUK_ASSERT(nc_ctx->count == 53 + 1);
 
59418
        DUK_ASSERT(nc_ctx->digits[0] == 1);  /* zero handled by caller */
 
59419
 
 
59420
        /* Should not be required because the code below always sets both high
 
59421
         * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
 
59422
         * (perhaps because the low part is set (seemingly) conditionally in a
 
59423
         * loop), so this is here to avoid the bogus warning.
 
59424
         */
 
59425
        DUK_MEMZERO((void *) &u, sizeof(u));
 
59426
 
 
59427
        /*
 
59428
         *  Figure out how generated digits match up with the mantissa,
 
59429
         *  and then perform rounding.  If mantissa overflows, need to
 
59430
         *  recompute the exponent (it is bumped and may overflow to
 
59431
         *  infinity).
 
59432
         *
 
59433
         *  For normal numbers the leading '1' is hidden and ignored,
 
59434
         *  and the last bit is used for rounding:
 
59435
         *
 
59436
         *                          rounding pt
 
59437
         *       <--------52------->|
 
59438
         *     1 x x x x ... x x x x|y  ==>  x x x x ... x x x x
 
59439
         *
 
59440
         *  For denormals, the leading '1' is included in the number,
 
59441
         *  and the rounding point is different:
 
59442
         *
 
59443
         *                      rounding pt
 
59444
         *     <--52 or less--->|
 
59445
         *     1 x x x x ... x x|x x y  ==>  0 0 ... 1 x x ... x x
 
59446
         *
 
59447
         *  The largest denormals will have a mantissa beginning with
 
59448
         *  a '1' (the explicit leading bit); smaller denormals will
 
59449
         *  have leading zero bits.
 
59450
         *
 
59451
         *  If the exponent would become too high, the result becomes
 
59452
         *  Infinity.  If the exponent is so small that the entire
 
59453
         *  mantissa becomes zero, the result becomes zero.
 
59454
         *
 
59455
         *  Note: the Dragon4 'k' is off-by-one with respect to the IEEE
 
59456
         *  exponent.  For instance, k==0 indicates that the leading '1'
 
59457
         *  digit is at the first binary fraction position (0.1xxx...);
 
59458
         *  the corresponding IEEE exponent would be -1.
 
59459
         */
 
59460
 
 
59461
        skip_round = 0;
 
59462
 
 
59463
 recheck_exp:
 
59464
 
 
59465
        exp = nc_ctx->k - 1;   /* IEEE exp without bias */
 
59466
        if (exp > 1023) {
 
59467
                /* Infinity */
 
59468
                bitstart = -255;  /* needed for inf: causes mantissa to become zero,
 
59469
                                   * and rounding to be skipped.
 
59470
                                   */
 
59471
                exp = 2047;
 
59472
        } else if (exp >= -1022) {
 
59473
                /* normal */
 
59474
                bitstart = 1;  /* skip leading digit */
 
59475
                exp += DUK__IEEE_DOUBLE_EXP_BIAS;
 
59476
                DUK_ASSERT(exp >= 1 && exp <= 2046);
 
59477
        } else {
 
59478
                /* denormal or zero */
 
59479
                bitstart = 1023 + exp;  /* exp==-1023 -> bitstart=0 (leading 1);
 
59480
                                         * exp==-1024 -> bitstart=-1 (one left of leading 1), etc
 
59481
                                         */
 
59482
                exp = 0;
 
59483
        }
 
59484
        bitround = bitstart + 52;
 
59485
 
 
59486
        DUK_DDDPRINT("ieee exp=%d, bitstart=%d, bitround=%d",
 
59487
                     (int) exp, (int) bitstart, (int) bitround);
 
59488
 
 
59489
        if (!skip_round) {
 
59490
                if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
 
59491
                        /* Corner case: see test-numconv-parse-mant-carry.js.  We could
 
59492
                         * just bump the exponent and update bitstart, but it's more robust
 
59493
                         * to recompute (but avoid rounding twice).
 
59494
                         */
 
59495
                        DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent");
 
59496
                        skip_round = 1;
 
59497
                        goto recheck_exp;
 
59498
                }
 
59499
        }
 
59500
 
 
59501
        /*
 
59502
         *  Create mantissa
 
59503
         */
 
59504
 
 
59505
        t = 0;
 
59506
        for (i = 0; i < 52; i++) {
 
59507
                bitidx = bitstart + 52 - 1 - i;
 
59508
                if (bitidx >= nc_ctx->count) {
 
59509
                        v = 0;
 
59510
                } else if (bitidx < 0) {
 
59511
                        v = 0;
 
59512
                } else {
 
59513
                        v = nc_ctx->digits[bitidx];
 
59514
                }
 
59515
                DUK_ASSERT(v == 0 || v == 1);
 
59516
                t += v << (i % 32);
 
59517
                if (i == 31) {
 
59518
                        /* low 32 bits is complete */
 
59519
                        DUK_DBLUNION_SET_LOW32(&u, t);
 
59520
                        t = 0;
 
59521
                }
 
59522
        }
 
59523
        /* t has high mantissa */
 
59524
 
 
59525
        DUK_DDDPRINT("mantissa is complete: %08x %08x",
 
59526
                     (unsigned int) t,
 
59527
                     (unsigned int) DUK_DBLUNION_GET_LOW32(&u));
 
59528
 
 
59529
        DUK_ASSERT(exp >= 0 && exp <= 0x7ffL);
 
59530
        t += exp << 20;
 
59531
#if 0  /* caller handles sign change */
 
59532
        if (negative) {
 
59533
                t |= 0x80000000U;
 
59534
        }
 
59535
#endif
 
59536
        DUK_DBLUNION_SET_HIGH32(&u, t);
 
59537
 
 
59538
        DUK_DDDPRINT("number is complete: %08x %08x",
 
59539
                     (unsigned int) DUK_DBLUNION_GET_HIGH32(&u),
 
59540
                     (unsigned int) DUK_DBLUNION_GET_LOW32(&u));
 
59541
 
 
59542
        *x = DUK_DBLUNION_GET_DOUBLE(&u);
 
59543
}
 
59544
 
 
59545
/*
 
59546
 *  Exposed number-to-string API
 
59547
 *
 
59548
 *  Input: [ number ]
 
59549
 *  Output: [ string ]
 
59550
 */
 
59551
 
 
59552
void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
 
59553
        duk_double_t x;
 
59554
        duk_small_int_t c;
 
59555
        duk_small_int_t neg;
 
59556
        duk_uint32_t uval;
 
59557
        duk__numconv_stringify_ctx nc_ctx_alloc;  /* large context; around 2kB now */
 
59558
        duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
 
59559
 
 
59560
        x = (duk_double_t) duk_require_number(ctx, -1);
 
59561
        duk_pop(ctx);
 
59562
 
 
59563
        /*
 
59564
         *  Handle special cases (NaN, infinity, zero).
 
59565
         */
 
59566
 
 
59567
        c = (duk_small_int_t) DUK_FPCLASSIFY(x);
 
59568
        if (DUK_SIGNBIT((double) x)) {
 
59569
                x = -x;
 
59570
                neg = 1;
 
59571
        } else {
 
59572
                neg = 0;
 
59573
        }
 
59574
 
 
59575
        /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
 
59576
        DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
 
59577
 
 
59578
        if (c == DUK_FP_NAN) {
 
59579
                duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
 
59580
                return;
 
59581
        } else if (c == DUK_FP_INFINITE) {
 
59582
                if (neg) {
 
59583
                        /* -Infinity */
 
59584
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
 
59585
                } else {
 
59586
                        /* Infinity */
 
59587
                        duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
 
59588
                }
 
59589
                return;
 
59590
        } else if (c == DUK_FP_ZERO) {
 
59591
                /* We can't shortcut zero here if it goes through special formatting
 
59592
                 * (such as forced exponential notation).
 
59593
                 */
 
59594
                ;
 
59595
        }
 
59596
 
 
59597
        /*
 
59598
         *  Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
 
59599
         *  specially, as they're very likely for embedded programs.  This
 
59600
         *  is now done for all radix values.  We must be careful not to use
 
59601
         *  the fast path when special formatting (e.g. forced exponential)
 
59602
         *  is in force.
 
59603
         *
 
59604
         *  XXX: could save space by supporting radix 10 only and using
 
59605
         *  sprintf "%u" for the fast path and for exponent formatting.
 
59606
         */
 
59607
 
 
59608
        uval = (unsigned int) x;
 
59609
        if (((double) uval) == x &&  /* integer number in range */
 
59610
            flags == 0) {            /* no special formatting */
 
59611
                /* use bigint area as a temp */
 
59612
                duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
 
59613
                duk_uint8_t *p = buf;
 
59614
 
 
59615
                DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1);  /* max size: radix=2 + sign */
 
59616
                if (neg && uval != 0) {
 
59617
                        /* no negative sign for zero */
 
59618
                        *p++ = (duk_uint8_t) '-';
 
59619
                }
 
59620
                p += duk__dragon4_format_uint32(p, uval, radix);
 
59621
                duk_push_lstring(ctx, (const char *) buf, (size_t) (p - buf));
 
59622
                return;
 
59623
        }
 
59624
 
 
59625
        /*
 
59626
         *  Dragon4 setup.
 
59627
         *
 
59628
         *  Convert double from IEEE representation for conversion;
 
59629
         *  normal finite values have an implicit leading 1-bit.  The
 
59630
         *  slow path algorithm doesn't handle zero, so zero is special
 
59631
         *  cased here but still creates a valid nc_ctx, and goes
 
59632
         *  through normal formatting in case special formatting has
 
59633
         *  been requested (e.g. forced exponential format: 0 -> "0e+0").
 
59634
         */
 
59635
 
 
59636
        /* Would be nice to bulk clear the allocation, but the context
 
59637
         * is 1-2 kilobytes and nothing should rely on it being zeroed.
 
59638
         */
 
59639
#if 0
 
59640
        DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx));  /* slow init, do only for slow path cases */
 
59641
#endif
 
59642
 
 
59643
        nc_ctx->is_s2n = 0;
 
59644
        nc_ctx->b = 2;
 
59645
        nc_ctx->B = radix;
 
59646
        nc_ctx->abs_pos = 0;
 
59647
        if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
 
59648
                nc_ctx->is_fixed = 1;
 
59649
                if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
 
59650
                        /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
 
59651
                         * but add an extra digit for rounding.
 
59652
                         */
 
59653
                        nc_ctx->abs_pos = 1;
 
59654
                        nc_ctx->req_digits = (-digits + 1) - 1;
 
59655
                } else {
 
59656
                        nc_ctx->req_digits = digits + 1;
 
59657
                }
 
59658
        } else {
 
59659
                nc_ctx->is_fixed = 0;
 
59660
                nc_ctx->req_digits = 0;
 
59661
        }
 
59662
 
 
59663
        if (c == DUK_FP_ZERO) {
 
59664
                /* Zero special case: fake requested number of zero digits; ensure
 
59665
                 * no sign bit is printed.  Relative and absolute fixed format
 
59666
                 * require separate handling.
 
59667
                 */
 
59668
                duk_small_int_t count;
 
59669
                if (nc_ctx->is_fixed) {
 
59670
                        if (nc_ctx->abs_pos) {
 
59671
                                count = digits + 2;  /* lead zero + 'digits' fractions + 1 for rounding */
 
59672
                        } else {
 
59673
                                count = digits + 1;  /* + 1 for rounding */
 
59674
                        }
 
59675
                } else {
 
59676
                        count = 1;
 
59677
                }
 
59678
                DUK_DDDPRINT("count=%d", (int) count);
 
59679
                DUK_ASSERT(count >= 1);
 
59680
                DUK_MEMZERO((void *) nc_ctx->digits, count);
 
59681
                nc_ctx->count = count;
 
59682
                nc_ctx->k = 1;  /* 0.000... */
 
59683
                neg = 0;
 
59684
                goto zero_skip;
 
59685
        }
 
59686
 
 
59687
        duk__dragon4_double_to_ctx(nc_ctx, x);   /* -> sets 'f' and 'e' */
 
59688
        DUK__BI_PRINT("f", &nc_ctx->f);
 
59689
        DUK_DDDPRINT("e=%d", (int) nc_ctx->e);
 
59690
 
 
59691
        /*
 
59692
         *  Dragon4 slow path digit generation.
 
59693
         */
 
59694
 
 
59695
        duk__dragon4_prepare(nc_ctx);  /* setup many variables in nc_ctx */
 
59696
 
 
59697
        DUK_DDDPRINT("after prepare:");
 
59698
        DUK__BI_PRINT("r", &nc_ctx->r);
 
59699
        DUK__BI_PRINT("s", &nc_ctx->s);
 
59700
        DUK__BI_PRINT("mp", &nc_ctx->mp);
 
59701
        DUK__BI_PRINT("mm", &nc_ctx->mm);
 
59702
 
 
59703
        duk__dragon4_scale(nc_ctx);
 
59704
 
 
59705
        DUK_DDDPRINT("after scale; k=%d", (int) nc_ctx->k);
 
59706
        DUK__BI_PRINT("r", &nc_ctx->r);
 
59707
        DUK__BI_PRINT("s", &nc_ctx->s);
 
59708
        DUK__BI_PRINT("mp", &nc_ctx->mp);
 
59709
        DUK__BI_PRINT("mm", &nc_ctx->mm);
 
59710
 
 
59711
        duk__dragon4_generate(nc_ctx);
 
59712
 
 
59713
        /*
 
59714
         *  Convert and push final string.
 
59715
         */
 
59716
 
 
59717
 zero_skip:
 
59718
 
 
59719
        if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
 
59720
                /* Perform fixed-format rounding. */
 
59721
                duk_small_int_t roundpos;
 
59722
                if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
 
59723
                        /* 'roundpos' is relative to nc_ctx->k and increases to the right
 
59724
                         * (opposite of how 'k' changes).
 
59725
                         */
 
59726
                        roundpos = -digits;  /* absolute position for digit considered for rounding */
 
59727
                        roundpos = nc_ctx->k - roundpos;
 
59728
                        
 
59729
                } else {
 
59730
                        roundpos = digits;
 
59731
                }
 
59732
                DUK_DDDPRINT("rounding: k=%d, count=%d, digits=%d, roundpos=%d",
 
59733
                             (int) nc_ctx->k, (int) nc_ctx->count, (int) digits, (int) roundpos);
 
59734
                (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
 
59735
 
 
59736
                /* Note: 'count' is currently not adjusted by rounding (i.e. the
 
59737
                 * digits are not "chopped off".  That shouldn't matter because
 
59738
                 * the digit position (absolute or relative) is passed on to the
 
59739
                 * convert-and-push function.
 
59740
                 */
 
59741
        }
 
59742
 
 
59743
        duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
 
59744
}
 
59745
 
 
59746
/*
 
59747
 *  Exposed string-to-number API
 
59748
 *
 
59749
 *  Input: [ string ]
 
59750
 *  Output: [ number ]
 
59751
 *
 
59752
 *  If number parsing fails, a NaN is pushed as the result.  If number parsing
 
59753
 *  fails due to an internal error, an InternalError is thrown.
 
59754
 */
 
59755
 
 
59756
void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
 
59757
        duk_hthread *thr = (duk_hthread *) ctx;
 
59758
        duk__numconv_stringify_ctx nc_ctx_alloc;  /* large context; around 2kB now */
 
59759
        duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
 
59760
        duk_double_t res;
 
59761
        duk_hstring *h_str;
 
59762
        duk_small_int_t exp;
 
59763
        duk_small_int_t exp_neg;
 
59764
        duk_small_int_t exp_adj;
 
59765
        duk_small_int_t neg;
 
59766
        duk_small_int_t dig;
 
59767
        duk_small_int_t dig_whole;
 
59768
        duk_small_int_t dig_lzero;
 
59769
        duk_small_int_t dig_frac;
 
59770
        duk_small_int_t dig_exp;
 
59771
        duk_small_int_t dig_prec;
 
59772
        const duk__exp_limits *explim;
 
59773
        const duk_uint8_t *p;
 
59774
        duk_small_int_t ch;
 
59775
 
 
59776
        /* This seems to waste a lot of stack frame entries, but good compilers
 
59777
         * will compute these as needed below.  Some of these initial flags are
 
59778
         * also modified in the code below, so they can't all be removed.
 
59779
         */
 
59780
        duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
 
59781
        duk_small_int_t allow_exp = (flags & DUK_S2N_FLAG_ALLOW_EXP);
 
59782
        duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
 
59783
        duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
 
59784
        duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
 
59785
        duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
 
59786
        duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
 
59787
        duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
 
59788
        duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
 
59789
        duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
 
59790
        duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
 
59791
        duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
 
59792
        duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
 
59793
 
 
59794
        DUK_DDDPRINT("parse number: %!T, radix=%d, flags=0x%08x",
 
59795
                     duk_get_tval(ctx, -1), (int) radix, (unsigned int) flags);
 
59796
 
 
59797
        DUK_ASSERT(radix >= 2 && radix <= 36);
 
59798
        DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
 
59799
 
 
59800
        /*
 
59801
         *  Preliminaries: trim, sign, Infinity check
 
59802
         *
 
59803
         *  We rely on the interned string having a NUL terminator, which will
 
59804
         *  cause a parse failure wherever it is encountered.  As a result, we
 
59805
         *  don't need separate pointer checks.
 
59806
         *
 
59807
         *  There is no special parsing for 'NaN' in the specification although
 
59808
         *  'Infinity' (with an optional sign) is allowed in some contexts.
 
59809
         *  Some contexts allow plus/minus sign, while others only allow the
 
59810
         *  minus sign (like JSON.parse()).
 
59811
         *
 
59812
         *  Automatic hex number detection (leading '0x' or '0X') and octal
 
59813
         *  number detection (leading '0' followed by at least one octal digit)
 
59814
         *  is done here too.
 
59815
         */
 
59816
 
 
59817
        if (trim_white) {
 
59818
                /* Leading / trailing whitespace is sometimes accepted and
 
59819
                 * sometimes not.  After white space trimming, all valid input
 
59820
                 * characters are pure ASCII.
 
59821
                 */
 
59822
                duk_trim(ctx, -1);
 
59823
        }
 
59824
        h_str = duk_require_hstring(ctx, -1);
 
59825
        DUK_ASSERT(h_str != NULL);
 
59826
        p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
 
59827
 
 
59828
        neg = 0;
 
59829
        ch = *p;
 
59830
        if (ch == (duk_small_int_t) '+') {
 
59831
                if (!allow_plus) {
 
59832
                        DUK_DDDPRINT("parse failed: leading plus sign not allowed");
 
59833
                        goto parse_fail;
 
59834
                }
 
59835
                p++;
 
59836
        } else if (ch == (duk_small_int_t) '-') {
 
59837
                if (!allow_minus) {
 
59838
                        DUK_DDDPRINT("parse failed: leading minus sign not allowed");
 
59839
                        goto parse_fail;
 
59840
                }
 
59841
                p++;
 
59842
                neg = 1;
 
59843
        }
 
59844
 
 
59845
        ch = *p;
 
59846
        if (allow_infinity && ch == (duk_small_int_t) 'I') {
 
59847
                /* Don't check for Infinity unless the context allows it.
 
59848
                 * 'Infinity' is a valid integer literal in e.g. base-36:
 
59849
                 *
 
59850
                 *   parseInt('Infinity', 36)
 
59851
                 *   1461559270678
 
59852
                 */
 
59853
 
 
59854
                const duk_uint8_t *q;
 
59855
 
 
59856
                /* borrow literal Infinity from builtin string */
 
59857
                q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
 
59858
                if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
 
59859
                        if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
 
59860
                                DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed");
 
59861
                                goto parse_fail;
 
59862
                        } else {
 
59863
                                res = DUK_DOUBLE_INFINITY;
 
59864
                                goto negcheck_and_ret;
 
59865
                        }
 
59866
                }
 
59867
        }
 
59868
        if (ch == (duk_small_int_t) '0') {
 
59869
                duk_small_int_t detect_radix = 0;
 
59870
                ch = p[1];
 
59871
                if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
 
59872
                        DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent");
 
59873
                        detect_radix = 16;
 
59874
                        allow_empty = 0;  /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
 
59875
                        p += 2;
 
59876
                } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
 
59877
                        DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent");
 
59878
                        detect_radix = 8;
 
59879
                        allow_empty = 1;  /* interpret e.g. '09' as '0', not NaN */
 
59880
                        p += 1;
 
59881
                }
 
59882
                if (detect_radix > 0) {
 
59883
                        radix = detect_radix;
 
59884
                        allow_exp = 0;
 
59885
                        allow_frac = 0;
 
59886
                        allow_naked_frac = 0;
 
59887
                        allow_empty_frac = 0;
 
59888
                        allow_leading_zero = 1;  /* allow e.g. '0x0009' and '00077' */
 
59889
                }
 
59890
        }
 
59891
 
 
59892
        /*
 
59893
         *  Scan number and setup for Dragon4.
 
59894
         *
 
59895
         *  The fast path case is detected during setup: an integer which
 
59896
         *  can be converted without rounding, no net exponent.  The fast
 
59897
         *  path could be implemented as a separate scan, but may not really
 
59898
         *  be worth it: the multiplications for building 'f' are not
 
59899
         *  expensive when 'f' is small.
 
59900
         *
 
59901
         *  The significand ('f') must contain enough bits of (apparent)
 
59902
         *  accuracy, so that Dragon4 will generate enough binary output digits.
 
59903
         *  For decimal numbers, this means generating a 20-digit significand,
 
59904
         *  which should yield enough practical accuracy to parse IEEE doubles.
 
59905
         *  In fact, the Ecmascript specification explicitly allows an
 
59906
         *  implementation to treat digits beyond 20 as zeroes (and even
 
59907
         *  to round the 20th digit upwards).  For non-decimal numbers, the
 
59908
         *  appropriate number of digits has been precomputed for comparable
 
59909
         *  accuracy.
 
59910
         *
 
59911
         *  Digit counts:
 
59912
         *
 
59913
         *    [ dig_lzero ]
 
59914
         *      |
 
59915
         *     .+-..---[ dig_prec ]----.
 
59916
         *     |  ||                   |
 
59917
         *     0000123.456789012345678901234567890e+123456
 
59918
         *     |     | |                         |  |    |
 
59919
         *     `--+--' `------[ dig_frac ]-------'  `-+--'
 
59920
         *        |                                   |
 
59921
         *    [ dig_whole ]                       [ dig_exp ]
 
59922
         *
 
59923
         *    dig_frac and dig_exp are -1 if not present
 
59924
         *    dig_lzero is only computed for whole number part
 
59925
         *
 
59926
         *  Parsing state
 
59927
         *
 
59928
         *     Parsing whole part      dig_frac < 0 AND dig_exp < 0
 
59929
         *     Parsing fraction part   dig_frac >= 0 AND dig_exp < 0
 
59930
         *     Parsing exponent part   dig_exp >= 0   (dig_frac may be < 0 or >= 0)
 
59931
         * 
 
59932
         *  Note: in case we hit an implementation limit (like exponent range),
 
59933
         *  we should throw an error, NOT return NaN or Infinity.  Even with
 
59934
         *  very large exponent (or significand) values the final result may be
 
59935
         *  finite, so NaN/Infinity would be incorrect.
 
59936
         */
 
59937
 
 
59938
        duk__bi_set_small(&nc_ctx->f, 0);
 
59939
        dig_prec = 0;
 
59940
        dig_lzero = 0;
 
59941
        dig_whole = 0;
 
59942
        dig_frac = -1;
 
59943
        dig_exp = -1;
 
59944
        exp = 0;
 
59945
        exp_adj = 0;  /* essentially tracks digit position of lowest 'f' digit */
 
59946
        exp_neg = 0;
 
59947
        for (;;) {
 
59948
                ch = *p++;
 
59949
 
 
59950
                DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%d), exp=%d, exp_adj=%d, "
 
59951
                             "dig_whole=%d, dig_frac=%d, dig_exp=%d, dig_lzero=%d, dig_prec=%d",
 
59952
                             (void *) p, (ch >= 0x20 && ch <= 0x7e) ? ch : '?', (int) ch,
 
59953
                             (int) exp, (int) exp_adj, (int) dig_whole, (int) dig_frac,
 
59954
                             (int) dig_exp, (int) dig_lzero, (int) dig_prec);
 
59955
                DUK__BI_PRINT("f", &nc_ctx->f);
 
59956
 
 
59957
                /* Most common cases first. */
 
59958
                if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
 
59959
                        dig = (int) ch - '0' + 0;
 
59960
                } else if (ch == (duk_small_int_t) '.') {
 
59961
                        /* A leading digit is not required in some cases, e.g. accept ".123".
 
59962
                         * In other cases (JSON.parse()) a leading digit is required.  This
 
59963
                         * is checked for after the loop.
 
59964
                         */
 
59965
                        if (dig_frac >= 0 || dig_exp >= 0) {
 
59966
                                if (allow_garbage) {
 
59967
                                        DUK_DDDPRINT("garbage termination (invalid period)");
 
59968
                                        break;
 
59969
                                } else {
 
59970
                                        DUK_DDDPRINT("parse failed: period not allowed");
 
59971
                                        goto parse_fail;
 
59972
                                }
 
59973
                        }
 
59974
 
 
59975
                        if (!allow_frac) {
 
59976
                                /* Some contexts don't allow fractions at all; this can't be a
 
59977
                                 * post-check because the state ('f' and exp) would be incorrect.
 
59978
                                 */
 
59979
                                if (allow_garbage) {
 
59980
                                        DUK_DDDPRINT("garbage termination (invalid first period)");
 
59981
                                        break;
 
59982
                                } else {
 
59983
                                        DUK_DDDPRINT("parse failed: fraction part not allowed");
 
59984
                                }
 
59985
                        }
 
59986
 
 
59987
                        DUK_DDDPRINT("start fraction part");
 
59988
                        dig_frac = 0;
 
59989
                        continue;
 
59990
                } else if (ch == (duk_small_int_t) 0) {
 
59991
                        DUK_DDDPRINT("NUL termination");
 
59992
                        break;
 
59993
                } else if (allow_exp && dig_exp < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
 
59994
                        /* Note: we don't parse back exponent notation for anything else
 
59995
                         * than radix 10, so this is not an ambiguous check (e.g. hex
 
59996
                         * exponent values may have 'e' either as a significand digit
 
59997
                         * or as an exponent separator).
 
59998
                         *
 
59999
                         * If the exponent separator occurs twice, 'e' will be interpreted
 
60000
                         * as a digit (= 14) and will be rejected as an invalid decimal
 
60001
                         * digit.
 
60002
                         */
 
60003
 
 
60004
                        DUK_DDDPRINT("start exponent part");
 
60005
 
 
60006
                        /* Exponent without a sign or with a +/- sign is accepted
 
60007
                         * by all call sites (even JSON.parse()).
 
60008
                         */
 
60009
                        ch = *p;
 
60010
                        if (ch == (duk_small_int_t) '-') {
 
60011
                                exp_neg = 1;
 
60012
                                p++;
 
60013
                        } else if (ch == (duk_small_int_t) '+') {
 
60014
                                p++;
 
60015
                        }
 
60016
                        dig_exp = 0;
 
60017
                        continue;
 
60018
                } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
 
60019
                        dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
 
60020
                } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
 
60021
                        dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
 
60022
                } else {
 
60023
                        dig = 255;  /* triggers garbage digit check below */
 
60024
                }
 
60025
                DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
 
60026
 
 
60027
                if (dig >= radix) {
 
60028
                        if (allow_garbage) {
 
60029
                                DUK_DDDPRINT("garbage termination");
 
60030
                                break;
 
60031
                        } else {
 
60032
                                DUK_DDDPRINT("parse failed: trailing garbage or invalid digit");
 
60033
                                goto parse_fail;
 
60034
                        }
 
60035
                }
 
60036
 
 
60037
                if (dig_exp < 0) {
 
60038
                        /* whole or fraction digit */
 
60039
 
 
60040
                        if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
 
60041
                                /* significant from precision perspective */
 
60042
 
 
60043
                                duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
 
60044
                                if (f_zero && dig == 0) {
 
60045
                                        /* Leading zero is not counted towards precision digits; not
 
60046
                                         * in the integer part, nor in the fraction part.
 
60047
                                         */
 
60048
                                        if (dig_frac < 0) {
 
60049
                                                dig_lzero++;
 
60050
                                        }
 
60051
                                } else {
 
60052
                                        /* XXX: join these ops (multiply-accumulate), but only if
 
60053
                                         * code footprint decreases.
 
60054
                                         */
 
60055
                                        duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
 
60056
                                        duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
 
60057
                                        dig_prec++;
 
60058
                                }
 
60059
                        } else {
 
60060
                                /* Ignore digits beyond a radix-specific limit, but note them
 
60061
                                 * in exp_adj.
 
60062
                                 */
 
60063
                                exp_adj++;
 
60064
                        }
 
60065
        
 
60066
                        if (dig_frac >= 0) {
 
60067
                                dig_frac++;
 
60068
                                exp_adj--;
 
60069
                        } else {
 
60070
                                dig_whole++;
 
60071
                        }
 
60072
                } else {
 
60073
                        /* exponent digit */
 
60074
 
 
60075
                        exp = exp * radix + dig;
 
60076
                        if (exp > DUK_S2N_MAX_EXPONENT) {
 
60077
                                /* impose a reasonable exponent limit, so that exp
 
60078
                                 * doesn't need to get tracked using a bigint.
 
60079
                                 */
 
60080
                                DUK_DDDPRINT("parse failed: exponent too large");
 
60081
                                goto parse_int_error;
 
60082
                        }
 
60083
                        dig_exp++;
 
60084
                }
 
60085
        }
 
60086
 
 
60087
        /* Leading zero. */
 
60088
 
 
60089
        if (dig_lzero > 0 && dig_whole > 1) {
 
60090
                if (!allow_leading_zero) {
 
60091
                        DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part");
 
60092
                        goto parse_fail;
 
60093
                }
 
60094
        }
 
60095
 
 
60096
        /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
 
60097
 
 
60098
        if (dig_whole == 0) {
 
60099
                if (dig_frac == 0) {
 
60100
                        /* "." is not accepted in any format */
 
60101
                        DUK_DDDPRINT("parse failed: plain period without leading or trailing digits");
 
60102
                        goto parse_fail;
 
60103
                } else if (dig_frac > 0) {
 
60104
                        /* ".123" */
 
60105
                        if (!allow_naked_frac) {
 
60106
                                DUK_DDDPRINT("parse failed: fraction part not allowed without "
 
60107
                                             "leading integer digit(s)");
 
60108
                                goto parse_fail;
 
60109
                        }
 
60110
                } else {
 
60111
                        /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
 
60112
                        if (!allow_empty) {
 
60113
                                DUK_DDDPRINT("parse failed: empty string not allowed (as zero)");
 
60114
                                goto parse_fail;
 
60115
                        }
 
60116
                }
 
60117
        } else {
 
60118
                if (dig_frac == 0) {
 
60119
                        /* "123." is allowed in some formats */
 
60120
                        if (!allow_empty_frac) {
 
60121
                                DUK_DDDPRINT("parse failed: empty fractions");
 
60122
                                goto parse_fail;
 
60123
                        }
 
60124
                } else if (dig_frac > 0) {
 
60125
                        /* "123.456" */
 
60126
                        ;
 
60127
                } else {
 
60128
                        /* "123" */
 
60129
                        ;
 
60130
                }
 
60131
        }
 
60132
 
 
60133
        /* Exponent without digits (e.g. "1e" or "1e+").  If trailing garbage is
 
60134
         * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
 
60135
         */
 
60136
 
 
60137
        if (dig_exp == 0) {
 
60138
                if (!allow_garbage) {
 
60139
                        DUK_DDDPRINT("parse failed: empty exponent");
 
60140
                        goto parse_fail;
 
60141
                }
 
60142
                DUK_ASSERT(exp == 0);
 
60143
        }
 
60144
 
 
60145
        if (exp_neg) {
 
60146
                exp = -exp;
 
60147
        }
 
60148
        DUK_DDDPRINT("exp=%d, exp_adj=%d, net exponent -> %d",
 
60149
                     (int) exp, (int) exp_adj, (int) (exp + exp_adj));
 
60150
        exp += exp_adj;
 
60151
 
 
60152
        /* Fast path check. */
 
60153
 
 
60154
        if (nc_ctx->f.n <= 1 &&   /* 32-bit value */
 
60155
            exp == 0    /* no net exponent */) {
 
60156
                /* Fast path is triggered for no exponent and also for balanced exponent
 
60157
                 * and fraction parts, e.g. for "1.23e2" == "123".  Remember to respect
 
60158
                 * zero sign.
 
60159
                 */
 
60160
 
 
60161
                /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
 
60162
                DUK_DDDPRINT("fast path number parse");
 
60163
                if (nc_ctx->f.n == 1) {
 
60164
                        res = (double) nc_ctx->f.v[0];
 
60165
                } else {
 
60166
                        res = 0.0;
 
60167
                }
 
60168
                goto negcheck_and_ret;
 
60169
        }
 
60170
 
 
60171
        /* Significand ('f') padding. */
 
60172
 
 
60173
        while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
 
60174
                /* Pad significand with "virtual" zero digits so that Dragon4 will
 
60175
                 * have enough (apparent) precision to work with.
 
60176
                 */
 
60177
                DUK_DDDPRINT("dig_prec=%d, pad significand with zero", (int) dig_prec);
 
60178
                duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
 
60179
                DUK__BI_PRINT("f", &nc_ctx->f);
 
60180
                exp--;
 
60181
                dig_prec++;
 
60182
        }
 
60183
 
 
60184
        DUK_DDDPRINT("final exponent: %d", (int) exp);
 
60185
 
 
60186
        /* Detect zero special case. */
 
60187
 
 
60188
        if (nc_ctx->f.n == 0) {
 
60189
                /* This may happen even after the fast path check, if exponent is
 
60190
                 * not balanced (e.g. "0e1").  Remember to respect zero sign.
 
60191
                 */
 
60192
                DUK_DDDPRINT("significand is zero");
 
60193
                res = 0.0;
 
60194
                goto negcheck_and_ret;
 
60195
        }
 
60196
 
 
60197
 
 
60198
        /* Quick reject of too large or too small exponents.  This check
 
60199
         * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
 
60200
         * so zero check must be above.
 
60201
         */
 
60202
 
 
60203
        explim = &duk__str2num_exp_limits[radix - 2];
 
60204
        if (exp > explim->upper) {
 
60205
                DUK_DDDPRINT("exponent too large -> infinite");
 
60206
                res = (duk_double_t) DUK_DOUBLE_INFINITY;
 
60207
                goto negcheck_and_ret;
 
60208
        } else if (exp < explim->lower) {
 
60209
                DUK_DDDPRINT("exponent too small -> zero");
 
60210
                res = (duk_double_t) 0.0;
 
60211
                goto negcheck_and_ret;
 
60212
        }
 
60213
 
 
60214
        nc_ctx->is_s2n = 1;
 
60215
        nc_ctx->e = exp;
 
60216
        nc_ctx->b = radix;
 
60217
        nc_ctx->B = 2;
 
60218
        nc_ctx->is_fixed = 1;
 
60219
        nc_ctx->abs_pos = 0;
 
60220
        nc_ctx->req_digits = 53 + 1;
 
60221
 
 
60222
        DUK__BI_PRINT("f", &nc_ctx->f);
 
60223
        DUK_DDDPRINT("e=%d", (int) nc_ctx->e);
 
60224
 
 
60225
        /*
 
60226
         *  Dragon4 slow path (binary) digit generation.
 
60227
         *  An extra digit is generated for rounding.
 
60228
         */
 
60229
 
 
60230
        duk__dragon4_prepare(nc_ctx);  /* setup many variables in nc_ctx */
 
60231
 
 
60232
        DUK_DDDPRINT("after prepare:");
 
60233
        DUK__BI_PRINT("r", &nc_ctx->r);
 
60234
        DUK__BI_PRINT("s", &nc_ctx->s);
 
60235
        DUK__BI_PRINT("mp", &nc_ctx->mp);
 
60236
        DUK__BI_PRINT("mm", &nc_ctx->mm);
 
60237
 
 
60238
        duk__dragon4_scale(nc_ctx);
 
60239
 
 
60240
        DUK_DDDPRINT("after scale; k=%d", (int) nc_ctx->k);
 
60241
        DUK__BI_PRINT("r", &nc_ctx->r);
 
60242
        DUK__BI_PRINT("s", &nc_ctx->s);
 
60243
        DUK__BI_PRINT("mp", &nc_ctx->mp);
 
60244
        DUK__BI_PRINT("mm", &nc_ctx->mm);
 
60245
 
 
60246
        duk__dragon4_generate(nc_ctx);
 
60247
 
 
60248
        DUK_ASSERT(nc_ctx->count == 53 + 1);
 
60249
 
 
60250
        /*
 
60251
         *  Convert binary digits into an IEEE double.  Need to handle
 
60252
         *  denormals and rounding correctly.
 
60253
         */
 
60254
 
 
60255
        duk__dragon4_ctx_to_double(nc_ctx, &res);
 
60256
        goto negcheck_and_ret;
 
60257
 
 
60258
 negcheck_and_ret:
 
60259
        if (neg) {
 
60260
                res = -res;
 
60261
        }
 
60262
        duk_pop(ctx);
 
60263
        duk_push_number(ctx, (double) res);
 
60264
        DUK_DDDPRINT("result: %!T", duk_get_tval(ctx, -1));
 
60265
        return;
 
60266
 
 
60267
 parse_fail:
 
60268
        DUK_DDDPRINT("parse failed");
 
60269
        duk_pop(ctx);
 
60270
        duk_push_nan(ctx);
 
60271
        return;
 
60272
 
 
60273
 parse_int_error:
 
60274
        DUK_DDDPRINT("parse failed, internal error, can't return a value");
 
60275
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "number parse error");
 
60276
        return;
 
60277
}
 
60278
 
 
60279
#line 1 "duk_regexp_compiler.c"
 
60280
/*
 
60281
 *  Regexp compilation.
 
60282
 *
 
60283
 *  See doc/regexp.txt for a discussion of the compilation approach and
 
60284
 *  current limitations.
 
60285
 */
 
60286
 
 
60287
/* include removed: duk_internal.h */
 
60288
 
 
60289
#ifdef DUK_USE_REGEXP_SUPPORT
 
60290
 
 
60291
/*
 
60292
 *  Helper macros
 
60293
 */
 
60294
 
 
60295
#ifdef DUK__BUFLEN
 
60296
#undef DUK__BUFLEN
 
60297
#endif
 
60298
 
 
60299
#define DUK__BUFLEN(re_ctx)   DUK_HBUFFER_GET_SIZE((duk_hbuffer *) re_ctx->buf)
 
60300
 
 
60301
/*
 
60302
 *  Disjunction struct: result of parsing a disjunction
 
60303
 */
 
60304
 
 
60305
typedef struct {
 
60306
        /* Number of characters that the atom matches (e.g. 3 for 'abc'),
 
60307
         * -1 if atom is complex and number of matched characters either
 
60308
         * varies or is not known.
 
60309
         */
 
60310
        duk_int32_t charlen;
 
60311
 
 
60312
#if 0
 
60313
        /* These are not needed to implement quantifier capture handling,
 
60314
         * but might be needed at some point.
 
60315
         */
 
60316
 
 
60317
        /* re_ctx->captures at start and end of atom parsing.
 
60318
         * Since 'captures' indicates highest capture number emitted
 
60319
         * so far in a DUK_REOP_SAVE, the captures numbers saved by
 
60320
         * the atom are: ]start_captures,end_captures].
 
60321
         */
 
60322
        duk_uint32_t start_captures;
 
60323
        duk_uint32_t end_captures;
 
60324
#endif
 
60325
} duk__re_disjunction_info;
 
60326
 
 
60327
/*
 
60328
 *  Encoding helpers
 
60329
 *
 
60330
 *  Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
 
60331
 *  even though the buffer operations will use duk_size_t.
 
60332
 */
 
60333
 
 
60334
/* XXX: the insert helpers should ensure that the bytecode result is not
 
60335
 * larger than expected (or at least assert for it).  Many things in the
 
60336
 * bytecode, like skip offsets, won't work correctly if the bytecode is
 
60337
 * larger than say 2G.
 
60338
 */
 
60339
 
 
60340
static duk_uint32_t duk__encode_i32(duk_int32_t x) {
 
60341
        if (x < 0) {
 
60342
                return ((duk_uint32_t) (-x)) * 2 + 1;
 
60343
        } else {
 
60344
                return ((duk_uint32_t) x) * 2;
 
60345
        }
 
60346
}
 
60347
 
 
60348
static duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
 
60349
        return duk_hbuffer_insert_xutf8(re_ctx->thr, re_ctx->buf, offset, x);
 
60350
}
 
60351
 
 
60352
static duk_uint32_t duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
 
60353
        return duk_hbuffer_append_xutf8(re_ctx->thr, re_ctx->buf, x);
 
60354
}
 
60355
 
 
60356
static duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
 
60357
        return duk_hbuffer_insert_xutf8(re_ctx->thr, re_ctx->buf, offset, duk__encode_i32(x));
 
60358
}
 
60359
 
 
60360
#if 0  /* unused */
 
60361
static duk_uint32_t duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
 
60362
        return duk_hbuffer_append_xutf8(re_ctx->thr, re_ctx->buf, duk__encode_i32(x));
 
60363
}
 
60364
#endif
 
60365
 
 
60366
/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
 
60367
static void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, duk_uint16_t *values, duk_uint32_t count) {
 
60368
        /* Call sites don't need the result length so it's not accumulated. */
 
60369
        while (count > 0) {
 
60370
                (void) duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
 
60371
                count--;
 
60372
        }
 
60373
}
 
60374
 
 
60375
static void duk__insert_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t data_offset, duk_uint32_t data_length) {
 
60376
        duk_hbuffer_insert_slice(re_ctx->thr, re_ctx->buf, offset, data_offset, (duk_size_t) data_length);
 
60377
}
 
60378
 
 
60379
static void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
 
60380
        duk_hbuffer_append_slice(re_ctx->thr, re_ctx->buf, data_offset, (duk_size_t) data_length);
 
60381
}
 
60382
 
 
60383
static void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t length) {
 
60384
        duk_hbuffer_remove_slice(re_ctx->thr, re_ctx->buf, offset, (duk_size_t) length);
 
60385
}
 
60386
 
 
60387
/*
 
60388
 *  Insert a jump offset at 'offset' to complete an instruction
 
60389
 *  (the jump offset is always the last component of an instruction).
 
60390
 *  The 'skip' argument must be computed relative to 'offset',
 
60391
 *  -without- taking into account the skip field being inserted.
 
60392
 *
 
60393
 *       ... A B C ins X Y Z ...   (ins may be a JUMP, SPLIT1/SPLIT2, etc)
 
60394
 *   =>  ... A B C ins SKIP X Y Z
 
60395
 *
 
60396
 *  Computing the final (adjusted) skip value, which is relative to the
 
60397
 *  first byte of the next instruction, is a bit tricky because of the
 
60398
 *  variable length UTF-8 encoding.  See doc/regexp.txt for discussion.
 
60399
 */
 
60400
static duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
 
60401
        duk_small_int_t len;
 
60402
 
 
60403
        /* XXX: solve into closed form (smaller code) */
 
60404
 
 
60405
        if (skip < 0) {
 
60406
                /* two encoding attempts suffices */
 
60407
                len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
 
60408
                len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
 
60409
                DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len);  /* no change */
 
60410
                skip -= (duk_int32_t) len;
 
60411
        }
 
60412
        return duk__insert_i32(re_ctx, offset, skip);
 
60413
}
 
60414
 
 
60415
static duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
 
60416
        return duk__insert_jump_offset(re_ctx, DUK__BUFLEN(re_ctx), skip);
 
60417
}
 
60418
 
 
60419
/*
 
60420
 *  duk_re_range_callback for generating character class ranges.
 
60421
 *
 
60422
 *  When ignoreCase is false, the range is simply emitted as is.
 
60423
 *  We don't, for instance, eliminate duplicates or overlapping
 
60424
 *  ranges in a character class.
 
60425
 *
 
60426
 *  When ignoreCase is true, the range needs to be normalized through
 
60427
 *  canonicalization.  Unfortunately a canonicalized version of a
 
60428
 *  continuous range is not necessarily continuous (e.g. [x-{] is
 
60429
 *  continuous but [X-{] is not).  The current algorithm creates the
 
60430
 *  canonicalized range(s) space efficiently at the cost of compile
 
60431
 *  time execution time (see doc/regexp.txt for discussion).
 
60432
 *
 
60433
 *  Note that the ctx->nranges is a context-wide temporary value
 
60434
 *  (this is OK because there cannot be multiple character classes
 
60435
 *  being parsed simultaneously).
 
60436
 */
 
60437
 
 
60438
static void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, int direct) {
 
60439
        duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
 
60440
 
 
60441
        DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%d,%d] direct=%d",
 
60442
                    (void *) re_ctx, (int) r1, (int) r2, (int) direct);
 
60443
 
 
60444
        if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
 
60445
                /*
 
60446
                 *  Canonicalize a range, generating result ranges as necessary.
 
60447
                 *  Needs to exhaustively scan the entire range (at most 65536
 
60448
                 *  code points).  If 'direct' is set, caller (lexer) has ensured
 
60449
                 *  that the range is already canonicalization compatible (this
 
60450
                 *  is used to avoid unnecessary canonicalization of built-in
 
60451
                 *  ranges like \W, which are not affected by canonicalization).
 
60452
                 *
 
60453
                 *  NOTE: here is one place where we don't want to support chars
 
60454
                 *  outside the BMP, because the exhaustive search would be
 
60455
                 *  massively larger.
 
60456
                 */
 
60457
 
 
60458
                duk_codepoint_t i;
 
60459
                duk_codepoint_t t;
 
60460
                duk_codepoint_t r_start, r_end;
 
60461
 
 
60462
                r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
 
60463
                r_end = r_start;
 
60464
                for (i = r1 + 1; i <= r2; i++) {
 
60465
                        t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
 
60466
                        if (t == r_end + 1) {
 
60467
                                r_end = t;
 
60468
                        } else {
 
60469
                                DUK_DDPRINT("canonicalized, emit range: [%d,%d]", (int) r_start, (int) r_end);
 
60470
                                duk__append_u32(re_ctx, (duk_uint32_t) r_start);
 
60471
                                duk__append_u32(re_ctx, (duk_uint32_t) r_end);
 
60472
                                re_ctx->nranges++;
 
60473
                                r_start = t;
 
60474
                                r_end = t;
 
60475
                        }
 
60476
                }
 
60477
                DUK_DDPRINT("canonicalized, emit range: [%d,%d]", r_start, r_end);
 
60478
                duk__append_u32(re_ctx, (duk_uint32_t) r_start);
 
60479
                duk__append_u32(re_ctx, (duk_uint32_t) r_end);
 
60480
                re_ctx->nranges++;
 
60481
        } else {
 
60482
                DUK_DDPRINT("direct, emit range: [%d,%d]", r1, r2);
 
60483
                duk__append_u32(re_ctx, (duk_uint32_t) r1);
 
60484
                duk__append_u32(re_ctx, (duk_uint32_t) r2);
 
60485
                re_ctx->nranges++;
 
60486
        }
 
60487
}
 
60488
 
 
60489
/*
 
60490
 *  Parse regexp Disjunction.  Most of regexp compilation happens here.
 
60491
 *
 
60492
 *  Handles Disjunction, Alternative, and Term productions directly without
 
60493
 *  recursion.  The only constructs requiring recursion are positive/negative
 
60494
 *  lookaheads, capturing parentheses, and non-capturing parentheses.
 
60495
 *
 
60496
 *  The function determines whether the entire disjunction is a 'simple atom'
 
60497
 *  (see doc/regexp.txt discussion on 'simple quantifiers') and if so,
 
60498
 *  returns the atom character length which is needed by the caller to keep
 
60499
 *  track of its own atom character length.  A disjunction with more than one
 
60500
 *  alternative is never considered a simple atom (although in some cases
 
60501
 *  that might be the case).
 
60502
 *
 
60503
 *  Return value: simple atom character length or < 0 if not a simple atom.
 
60504
 *  Appends the bytecode for the disjunction matcher to the end of the temp
 
60505
 *  buffer.
 
60506
 *
 
60507
 *  Regexp top level structure is:
 
60508
 *
 
60509
 *    Disjunction = Term*
 
60510
 *                | Term* | Disjunction
 
60511
 *
 
60512
 *    Term = Assertion
 
60513
 *         | Atom
 
60514
 *         | Atom Quantifier
 
60515
 *
 
60516
 *  An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
 
60517
 *
 
60518
 *  Notes:
 
60519
 *
 
60520
 *    * Tracking of the 'simple-ness' of the current atom vs. the entire
 
60521
 *      disjunction are separate matters.  For instance, the disjunction
 
60522
 *      may be complex, but individual atoms may be simple.  Furthermore,
 
60523
 *      simple quantifiers are used whenever possible, even if the
 
60524
 *      disjunction as a whole is complex.
 
60525
 *
 
60526
 *    * The estimate of whether an atom is simple is conservative now,
 
60527
 *      and it would be possible to expand it.  For instance, captures
 
60528
 *      cause the disjunction to be marked complex, even though captures
 
60529
 *      -can- be handled by simple quantifiers with some minor modifications.
 
60530
 *
 
60531
 *    * Disjunction 'tainting' as 'complex' is handled at the end of the
 
60532
 *      main for loop collectively for atoms.  Assertions, quantifiers,
 
60533
 *      and '|' tokens need to taint the result manually if necessary.
 
60534
 *      Assertions cannot add to result char length, only atoms (and
 
60535
 *      quantifiers) can; currently quantifiers will taint the result
 
60536
 *      as complex though.
 
60537
 */
 
60538
 
 
60539
static void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, int expect_eof, duk__re_disjunction_info *out_atom_info) {
 
60540
        duk_int32_t atom_start_offset = -1;                   /* negative -> no atom matched on previous round */
 
60541
        duk_int32_t atom_char_length = 0;                     /* negative -> complex atom */
 
60542
        duk_uint32_t atom_start_captures = re_ctx->captures;  /* value of re_ctx->captures at start of atom */
 
60543
        duk_int32_t unpatched_disjunction_split = -1;
 
60544
        duk_int32_t unpatched_disjunction_jump = -1;
 
60545
        duk_uint32_t entry_offset = DUK__BUFLEN(re_ctx);
 
60546
        duk_int32_t res_charlen = 0;  /* -1 if disjunction is complex, char length if simple */
 
60547
        duk__re_disjunction_info tmp_disj;
 
60548
 
 
60549
        DUK_ASSERT(out_atom_info != NULL);
 
60550
 
 
60551
        if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
 
60552
                DUK_ERROR(re_ctx->thr, DUK_ERR_INTERNAL_ERROR,
 
60553
                          "regexp compiler recursion limit reached");
 
60554
        }
 
60555
        re_ctx->recursion_depth++;
 
60556
 
 
60557
#if 0
 
60558
        out_atom_info->start_captures = re_ctx->captures;
 
60559
#endif
 
60560
 
 
60561
        for (;;) {
 
60562
                /* atom_char_length, atom_start_offset, atom_start_offset reflect the
 
60563
                 * atom matched on the previous loop.  If a quantifier is encountered
 
60564
                 * on this loop, these are needed to handle the quantifier correctly.
 
60565
                 * new_atom_char_length etc are for the atom parsed on this round;
 
60566
                 * they're written to atom_char_length etc at the end of the round.
 
60567
                 */
 
60568
                duk_int32_t new_atom_char_length;   /* char length of the atom parsed in this loop */
 
60569
                duk_int32_t new_atom_start_offset;  /* bytecode start offset of the atom parsed in this loop
 
60570
                                                     * (allows quantifiers to copy the atom bytecode)
 
60571
                                                     */
 
60572
                duk_uint32_t new_atom_start_captures;  /* re_ctx->captures at the start of the atom parsed in this loop */
 
60573
 
 
60574
                duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
 
60575
 
 
60576
                DUK_DDPRINT("re token: %d (num=%d, char=%c)",
 
60577
                            re_ctx->curr_token.t,
 
60578
                            re_ctx->curr_token.num,
 
60579
                            (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
 
60580
                            (char) re_ctx->curr_token.num : '?');
 
60581
 
 
60582
                /* set by atom case clauses */
 
60583
                new_atom_start_offset = -1;
 
60584
                new_atom_char_length = -1;
 
60585
                new_atom_start_captures = re_ctx->captures;
 
60586
 
 
60587
                switch (re_ctx->curr_token.t) {
 
60588
                case DUK_RETOK_DISJUNCTION: {
 
60589
                        /*
 
60590
                         *  The handling here is a bit tricky.  If a previous '|' has been processed,
 
60591
                         *  we have a pending split1 and a pending jump (for a previous match).  These
 
60592
                         *  need to be back-patched carefully.  See docs for a detailed example.
 
60593
                         */
 
60594
 
 
60595
                        /* patch pending jump and split */
 
60596
                        if (unpatched_disjunction_jump >= 0) {
 
60597
                                duk_uint32_t offset;
 
60598
 
 
60599
                                DUK_ASSERT(unpatched_disjunction_split >= 0);
 
60600
                                offset = unpatched_disjunction_jump;
 
60601
                                offset += duk__insert_jump_offset(re_ctx,
 
60602
                                                                  offset,
 
60603
                                                                  DUK__BUFLEN(re_ctx) - offset);
 
60604
                                /* offset is now target of the pending split (right after jump) */
 
60605
                                duk__insert_jump_offset(re_ctx,
 
60606
                                                        unpatched_disjunction_split,
 
60607
                                                        offset - unpatched_disjunction_split);
 
60608
                        }
 
60609
 
 
60610
                        /* add a new pending split to the beginning of the entire disjunction */
 
60611
                        (void) duk__insert_u32(re_ctx,
 
60612
                                               entry_offset,
 
60613
                                               DUK_REOP_SPLIT1);   /* prefer direct execution */
 
60614
                        unpatched_disjunction_split = entry_offset + 1;   /* +1 for opcode */
 
60615
 
 
60616
                        /* add a new pending match jump for latest finished alternative */
 
60617
                        duk__append_u32(re_ctx, DUK_REOP_JUMP);
 
60618
                        unpatched_disjunction_jump = DUK__BUFLEN(re_ctx);
 
60619
 
 
60620
                        /* 'taint' result as complex */
 
60621
                        res_charlen = -1;
 
60622
                        break;
 
60623
                }
 
60624
                case DUK_RETOK_QUANTIFIER: {
 
60625
                        if (atom_start_offset < 0) {
 
60626
                                DUK_ERROR(re_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
60627
                                          "quantifier without preceding atom");
 
60628
                        }
 
60629
                        if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
 
60630
                                DUK_ERROR(re_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
60631
                                          "quantifier values invalid (qmin > qmax)");
 
60632
                        }
 
60633
                        if (atom_char_length >= 0) {
 
60634
                                /*
 
60635
                                 *  Simple atom
 
60636
                                 *
 
60637
                                 *  If atom_char_length is zero, we'll have unbounded execution time for e.g.
 
60638
                                 *  /()*x/.exec('x').  We can't just skip the match because it might have some
 
60639
                                 *  side effects (for instance, if we allowed captures in simple atoms, the
 
60640
                                 *  capture needs to happen).  The simple solution below is to force the
 
60641
                                 *  quantifier to match at most once, since the additional matches have no effect.
 
60642
                                 *
 
60643
                                 *  With a simple atom there can be no capture groups, so no captures need
 
60644
                                 *  to be reset.
 
60645
                                 */
 
60646
                                duk_int32_t atom_code_length;
 
60647
                                duk_uint32_t offset;
 
60648
                                duk_uint32_t qmin, qmax;
 
60649
 
 
60650
                                qmin = re_ctx->curr_token.qmin;
 
60651
                                qmax = re_ctx->curr_token.qmax;
 
60652
                                if (atom_char_length == 0) {
 
60653
                                        /* qmin and qmax will be 0 or 1 */
 
60654
                                        if (qmin > 1) {
 
60655
                                                qmin = 1;
 
60656
                                        }
 
60657
                                        if (qmax > 1) {
 
60658
                                                qmax = 1;
 
60659
                                        }
 
60660
                                }
 
60661
 
 
60662
                                duk__append_u32(re_ctx, DUK_REOP_MATCH);   /* complete 'sub atom' */
 
60663
                                atom_code_length = DUK__BUFLEN(re_ctx) - atom_start_offset;
 
60664
 
 
60665
                                offset = atom_start_offset;
 
60666
                                if (re_ctx->curr_token.greedy) {
 
60667
                                        offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
 
60668
                                        offset += duk__insert_u32(re_ctx, offset, qmin);
 
60669
                                        offset += duk__insert_u32(re_ctx, offset, qmax);
 
60670
                                        offset += duk__insert_u32(re_ctx, offset, atom_char_length);
 
60671
                                        offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
 
60672
                                } else {
 
60673
                                        offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
 
60674
                                        offset += duk__insert_u32(re_ctx, offset, qmin);
 
60675
                                        offset += duk__insert_u32(re_ctx, offset, qmax);
 
60676
                                        offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
 
60677
                                }
 
60678
                                DUK_UNREF(offset);  /* silence scan-build warning */
 
60679
                        } else {
 
60680
                                /*
 
60681
                                 *  Complex atom
 
60682
                                 *
 
60683
                                 *  The original code is used as a template, and removed at the end
 
60684
                                 *  (this differs from the handling of simple quantifiers).
 
60685
                                 *
 
60686
                                 *  NOTE: there is no current solution for empty atoms in complex
 
60687
                                 *  quantifiers.  This would need some sort of a 'progress' instruction.
 
60688
                                 *
 
60689
                                 *  XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
 
60690
                                 */
 
60691
                                duk_int32_t atom_code_length;
 
60692
                                duk_uint32_t atom_copies;
 
60693
                                duk_uint32_t tmp_qmin, tmp_qmax;
 
60694
 
 
60695
                                /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
 
60696
                                atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
 
60697
                                              re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
 
60698
                                if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
 
60699
                                        DUK_ERROR(re_ctx->thr, DUK_ERR_INTERNAL_ERROR,
 
60700
                                                  "quantifier expansion requires too many atom copies");
 
60701
                                }
 
60702
 
 
60703
                                /* wipe the capture range made by the atom (if any) */
 
60704
                                DUK_ASSERT(atom_start_captures <= re_ctx->captures);
 
60705
                                if (atom_start_captures != re_ctx->captures) {
 
60706
                                        DUK_ASSERT(atom_start_captures < re_ctx->captures);
 
60707
                                        DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%d,%d]",
 
60708
                                                     (int) atom_start_captures, (int) re_ctx->captures);
 
60709
 
 
60710
                                        /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
 
60711
                                        duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
 
60712
                                        duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
 
60713
                                        duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
 
60714
                                } else {
 
60715
                                        DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %d",
 
60716
                                                     (int) atom_start_captures);
 
60717
                                }
 
60718
 
 
60719
                                atom_code_length = DUK__BUFLEN(re_ctx) - atom_start_offset;
 
60720
 
 
60721
                                /* insert the required matches (qmin) by copying the atom */
 
60722
                                tmp_qmin = re_ctx->curr_token.qmin;
 
60723
                                tmp_qmax = re_ctx->curr_token.qmax;
 
60724
                                while (tmp_qmin > 0) {
 
60725
                                        duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
 
60726
                                        tmp_qmin--;
 
60727
                                        if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
 
60728
                                                tmp_qmax--;
 
60729
                                        }
 
60730
                                }
 
60731
                                DUK_ASSERT(tmp_qmin == 0);
 
60732
 
 
60733
                                /* insert code for matching the remainder - infinite or finite */
 
60734
                                if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
 
60735
                                        /* reuse last emitted atom for remaining 'infinite' quantifier */
 
60736
 
 
60737
                                        if (re_ctx->curr_token.qmin == 0) {
 
60738
                                                /* Special case: original qmin was zero so there is nothing
 
60739
                                                 * to repeat.  Emit an atom copy but jump over it here.
 
60740
                                                 */
 
60741
                                                duk__append_u32(re_ctx, DUK_REOP_JUMP);
 
60742
                                                duk__append_jump_offset(re_ctx, atom_code_length);
 
60743
                                                duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
 
60744
                                        }
 
60745
                                        if (re_ctx->curr_token.greedy) {
 
60746
                                                duk__append_u32(re_ctx, DUK_REOP_SPLIT2);   /* prefer jump */
 
60747
                                        } else {
 
60748
                                                duk__append_u32(re_ctx, DUK_REOP_SPLIT1);   /* prefer direct */
 
60749
                                        }
 
60750
                                        duk__append_jump_offset(re_ctx, -atom_code_length - 1);  /* -1 for opcode */
 
60751
                                } else {
 
60752
                                        /*
 
60753
                                         *  The remaining matches are emitted as sequence of SPLITs and atom
 
60754
                                         *  copies; the SPLITs skip the remaining copies and match the sequel.
 
60755
                                         *  This sequence needs to be emitted starting from the last copy
 
60756
                                         *  because the SPLITs are variable length due to the variable length
 
60757
                                         *  skip offset.  This causes a lot of memory copying now.
 
60758
                                         *
 
60759
                                         *  Example structure (greedy, match maximum # atoms):
 
60760
                                         *
 
60761
                                         *      SPLIT1 LSEQ
 
60762
                                         *      (atom)
 
60763
                                         *      SPLIT1 LSEQ    ; <- the byte length of this instruction is needed
 
60764
                                         *      (atom)         ; to encode the above SPLIT1 correctly
 
60765
                                         *      ...
 
60766
                                         *   LSEQ:
 
60767
                                         */
 
60768
                                        duk_uint32_t offset = DUK__BUFLEN(re_ctx);
 
60769
                                        while (tmp_qmax > 0) {
 
60770
                                                duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
 
60771
                                                if (re_ctx->curr_token.greedy) {
 
60772
                                                        duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1);   /* prefer direct */
 
60773
                                                } else {
 
60774
                                                        duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2);   /* prefer jump */
 
60775
                                                }
 
60776
                                                duk__insert_jump_offset(re_ctx,
 
60777
                                                                        offset + 1,   /* +1 for opcode */
 
60778
                                                                        DUK__BUFLEN(re_ctx) - (offset + 1));
 
60779
                                                tmp_qmax--;
 
60780
                                        }
 
60781
                                }
 
60782
 
 
60783
                                /* remove the original 'template' atom */
 
60784
                                duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
 
60785
                        }
 
60786
 
 
60787
                        /* 'taint' result as complex */
 
60788
                        res_charlen = -1;
 
60789
                        break;
 
60790
                }
 
60791
                case DUK_RETOK_ASSERT_START: {
 
60792
                        duk__append_u32(re_ctx, DUK_REOP_ASSERT_START);
 
60793
                        break;
 
60794
                }
 
60795
                case DUK_RETOK_ASSERT_END: {
 
60796
                        duk__append_u32(re_ctx, DUK_REOP_ASSERT_END);
 
60797
                        break;
 
60798
                }
 
60799
                case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
 
60800
                        duk__append_u32(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
 
60801
                        break;
 
60802
                }
 
60803
                case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
 
60804
                        duk__append_u32(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
 
60805
                        break;
 
60806
                }
 
60807
                case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
 
60808
                case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
 
60809
                        duk_uint32_t offset;
 
60810
                        duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
 
60811
                                              DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
 
60812
 
 
60813
                        offset = DUK__BUFLEN(re_ctx);
 
60814
                        duk__parse_disjunction(re_ctx, 0, &tmp_disj);
 
60815
                        duk__append_u32(re_ctx, DUK_REOP_MATCH);
 
60816
 
 
60817
                        (void) duk__insert_u32(re_ctx, offset, opcode);
 
60818
                        (void) duk__insert_jump_offset(re_ctx,
 
60819
                                                       offset + 1,   /* +1 for opcode */
 
60820
                                                       DUK__BUFLEN(re_ctx) - (offset + 1));
 
60821
 
 
60822
                        /* 'taint' result as complex -- this is conservative,
 
60823
                         * as lookaheads do not backtrack.
 
60824
                         */
 
60825
                        res_charlen = -1;
 
60826
                        break;
 
60827
                }
 
60828
                case DUK_RETOK_ATOM_PERIOD: {
 
60829
                        new_atom_char_length = 1;
 
60830
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60831
                        duk__append_u32(re_ctx, DUK_REOP_PERIOD);
 
60832
                        break;
 
60833
                }
 
60834
                case DUK_RETOK_ATOM_CHAR: {
 
60835
                        /* Note: successive characters could be joined into string matches
 
60836
                         * but this is not trivial (consider e.g. '/xyz+/); see docs for
 
60837
                         * more discussion.
 
60838
                         */
 
60839
                        duk_uint32_t ch;
 
60840
 
 
60841
                        new_atom_char_length = 1;
 
60842
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60843
                        duk__append_u32(re_ctx, DUK_REOP_CHAR);
 
60844
                        ch = re_ctx->curr_token.num;
 
60845
                        if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
 
60846
                                ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
 
60847
                        }
 
60848
                        duk__append_u32(re_ctx, ch);
 
60849
                        break;
 
60850
                }
 
60851
                case DUK_RETOK_ATOM_DIGIT:
 
60852
                case DUK_RETOK_ATOM_NOT_DIGIT: {
 
60853
                        new_atom_char_length = 1;
 
60854
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60855
                        duk__append_u32(re_ctx,
 
60856
                                        (re_ctx->curr_token.t == DUK_RETOK_ATOM_DIGIT) ?
 
60857
                                        DUK_REOP_RANGES : DUK_REOP_INVRANGES);
 
60858
                        duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)));
 
60859
                        duk__append_u16_list(re_ctx, duk_unicode_re_ranges_digit, sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
 
60860
                        break;
 
60861
                }
 
60862
                case DUK_RETOK_ATOM_WHITE:
 
60863
                case DUK_RETOK_ATOM_NOT_WHITE: {
 
60864
                        new_atom_char_length = 1;
 
60865
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60866
                        duk__append_u32(re_ctx,
 
60867
                                        (re_ctx->curr_token.t == DUK_RETOK_ATOM_WHITE) ?
 
60868
                                        DUK_REOP_RANGES : DUK_REOP_INVRANGES);
 
60869
                        duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)));
 
60870
                        duk__append_u16_list(re_ctx, duk_unicode_re_ranges_white, sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
 
60871
                        break;
 
60872
                }
 
60873
                case DUK_RETOK_ATOM_WORD_CHAR:
 
60874
                case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
 
60875
                        new_atom_char_length = 1;
 
60876
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60877
                        duk__append_u32(re_ctx,
 
60878
                                        (re_ctx->curr_token.t == DUK_RETOK_ATOM_WORD_CHAR) ?
 
60879
                                        DUK_REOP_RANGES : DUK_REOP_INVRANGES);
 
60880
                        duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)));
 
60881
                        duk__append_u16_list(re_ctx, duk_unicode_re_ranges_wordchar, sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
 
60882
                        break;
 
60883
                }
 
60884
                case DUK_RETOK_ATOM_BACKREFERENCE: {
 
60885
                        duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
 
60886
                        if (backref > re_ctx->highest_backref) {
 
60887
                                re_ctx->highest_backref = backref;
 
60888
                        }
 
60889
                        new_atom_char_length = -1;   /* mark as complex */
 
60890
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60891
                        duk__append_u32(re_ctx, DUK_REOP_BACKREFERENCE);
 
60892
                        duk__append_u32(re_ctx, backref);
 
60893
                        break;
 
60894
                }
 
60895
                case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
 
60896
                        duk_uint32_t cap;
 
60897
 
 
60898
                        new_atom_char_length = -1;   /* mark as complex (capture handling) */
 
60899
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60900
                        cap = ++re_ctx->captures;
 
60901
                        duk__append_u32(re_ctx, DUK_REOP_SAVE);
 
60902
                        duk__append_u32(re_ctx, cap * 2);
 
60903
                        duk__parse_disjunction(re_ctx, 0, &tmp_disj);  /* retval (sub-atom char length) unused, tainted as complex above */
 
60904
                        duk__append_u32(re_ctx, DUK_REOP_SAVE);
 
60905
                        duk__append_u32(re_ctx, cap * 2 + 1);
 
60906
                        break;
 
60907
                }
 
60908
                case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
 
60909
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60910
                        duk__parse_disjunction(re_ctx, 0, &tmp_disj);
 
60911
                        new_atom_char_length = tmp_disj.charlen;
 
60912
                        break;
 
60913
                }
 
60914
                case DUK_RETOK_ATOM_START_CHARCLASS:
 
60915
                case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
 
60916
                        /*
 
60917
                         *  Range parsing is done with a special lexer function which calls
 
60918
                         *  us for every range parsed.  This is different from how rest of
 
60919
                         *  the parsing works, but avoids a heavy, arbitrary size intermediate
 
60920
                         *  value type to hold the ranges.
 
60921
                         *
 
60922
                         *  Another complication is the handling of character ranges when
 
60923
                         *  case insensitive matching is used (see docs for discussion).
 
60924
                         *  The range handler callback given to the lexer takes care of this
 
60925
                         *  as well.
 
60926
                         *
 
60927
                         *  Note that duplicate ranges are not eliminated when parsing character
 
60928
                         *  classes, so that canonicalization of
 
60929
                         *
 
60930
                         *    [0-9a-fA-Fx-{]
 
60931
                         *
 
60932
                         *  creates the result (note the duplicate ranges):
 
60933
                         *
 
60934
                         *    [0-9A-FA-FX-Z{-{]
 
60935
                         *
 
60936
                         *  where [x-{] is split as a result of canonicalization.  The duplicate
 
60937
                         *  ranges are not a semantics issue: they work correctly.
 
60938
                         */
 
60939
 
 
60940
                        duk_uint32_t offset;
 
60941
 
 
60942
                        DUK_DDPRINT("character class");
 
60943
 
 
60944
                        /* insert ranges instruction, range count patched in later */
 
60945
                        new_atom_char_length = 1;
 
60946
                        new_atom_start_offset = DUK__BUFLEN(re_ctx);
 
60947
                        duk__append_u32(re_ctx,
 
60948
                                        (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
 
60949
                                        DUK_REOP_RANGES : DUK_REOP_INVRANGES);
 
60950
                        offset = DUK__BUFLEN(re_ctx);    /* patch in range count later */
 
60951
 
 
60952
                        /* parse ranges until character class ends */
 
60953
                        re_ctx->nranges = 0;    /* note: ctx-wide temporary */
 
60954
                        duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
 
60955
 
 
60956
                        /* insert range count */
 
60957
                        duk__insert_u32(re_ctx, offset, re_ctx->nranges);
 
60958
                        break;
 
60959
                }
 
60960
                case DUK_RETOK_ATOM_END_GROUP: {
 
60961
                        if (expect_eof) {
 
60962
                                DUK_ERROR(re_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
60963
                                          "unexpected closing parenthesis");
 
60964
                        }
 
60965
                        goto done;
 
60966
                }
 
60967
                case DUK_RETOK_EOF: {
 
60968
                        if (!expect_eof) {
 
60969
                                DUK_ERROR(re_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
60970
                                          "unexpected end of pattern");
 
60971
                        }
 
60972
                        goto done;
 
60973
                }
 
60974
                default: {
 
60975
                        DUK_ERROR(re_ctx->thr, DUK_ERR_SYNTAX_ERROR,
 
60976
                                  "unexpected token in regexp");
 
60977
                }
 
60978
                }
 
60979
 
 
60980
                /* a complex (new) atom taints the result */
 
60981
                if (new_atom_start_offset >= 0) {
 
60982
                        if (new_atom_char_length < 0) {
 
60983
                                res_charlen = -1;
 
60984
                        } else if (res_charlen >= 0) {
 
60985
                                /* only advance if not tainted */
 
60986
                                res_charlen += new_atom_char_length;
 
60987
                        }
 
60988
                }
 
60989
 
 
60990
                /* record previous atom info in case next token is a quantifier */
 
60991
                atom_start_offset = new_atom_start_offset;
 
60992
                atom_char_length = new_atom_char_length;
 
60993
                atom_start_captures = new_atom_start_captures;
 
60994
        }
 
60995
 
 
60996
 done:
 
60997
 
 
60998
        /* finish up pending jump and split for last alternative */
 
60999
        if (unpatched_disjunction_jump >= 0) {
 
61000
                duk_uint32_t offset;
 
61001
 
 
61002
                DUK_ASSERT(unpatched_disjunction_split >= 0);
 
61003
                offset = unpatched_disjunction_jump;
 
61004
                offset += duk__insert_jump_offset(re_ctx,
 
61005
                                                  offset,
 
61006
                                                  DUK__BUFLEN(re_ctx) - offset);
 
61007
                /* offset is now target of the pending split (right after jump) */
 
61008
                duk__insert_jump_offset(re_ctx,
 
61009
                                        unpatched_disjunction_split,
 
61010
                                        offset - unpatched_disjunction_split);
 
61011
        }
 
61012
 
 
61013
#if 0
 
61014
        out_atom_info->end_captures = re_ctx->captures;
 
61015
#endif
 
61016
        out_atom_info->charlen = res_charlen;
 
61017
        DUK_DDDPRINT("parse disjunction finished: charlen=%d",
 
61018
                     (int) out_atom_info->charlen);
 
61019
 
 
61020
        re_ctx->recursion_depth--;
 
61021
}
 
61022
 
 
61023
/*
 
61024
 *  Flags parsing (see E5 Section 15.10.4.1).
 
61025
 */
 
61026
 
 
61027
static duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
 
61028
        duk_uint8_t *p;
 
61029
        duk_uint8_t *p_end;
 
61030
        duk_uint32_t flags = 0;
 
61031
 
 
61032
        p = DUK_HSTRING_GET_DATA(h);
 
61033
        p_end = p + DUK_HSTRING_GET_BYTELEN(h);
 
61034
 
 
61035
        /* Note: can be safely scanned as bytes (undecoded) */
 
61036
 
 
61037
        while (p < p_end) {
 
61038
                duk_uint8_t c = *p++;
 
61039
                switch ((int) c) {
 
61040
                case (int) 'g': {
 
61041
                        if (flags & DUK_RE_FLAG_GLOBAL) {
 
61042
                                goto error;
 
61043
                        }
 
61044
                        flags |= DUK_RE_FLAG_GLOBAL;
 
61045
                        break;
 
61046
                }
 
61047
                case (int) 'i': {
 
61048
                        if (flags & DUK_RE_FLAG_IGNORE_CASE) {
 
61049
                                goto error;
 
61050
                        }
 
61051
                        flags |= DUK_RE_FLAG_IGNORE_CASE;
 
61052
                        break;
 
61053
                }
 
61054
                case (int) 'm': {
 
61055
                        if (flags & DUK_RE_FLAG_MULTILINE) {
 
61056
                                goto error;
 
61057
                        }
 
61058
                        flags |= DUK_RE_FLAG_MULTILINE;
 
61059
                        break;
 
61060
                }
 
61061
                default: {
 
61062
                        goto error;
 
61063
                }
 
61064
                }
 
61065
        }
 
61066
 
 
61067
        return flags;
 
61068
 
 
61069
 error:
 
61070
        DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid regexp flags");
 
61071
        return 0;  /* never here */
 
61072
}
 
61073
 
 
61074
/*
 
61075
 *  Create escaped RegExp source (E5 Section 15.10.3).
 
61076
 *
 
61077
 *  The current approach is to special case the empty RegExp
 
61078
 *  ('' -> '(?:)') and otherwise replace unescaped '/' characters
 
61079
 *  with '\/' regardless of where they occur in the regexp.
 
61080
 *
 
61081
 *  Note that normalization does not seem to be necessary for
 
61082
 *  RegExp literals (e.g. '/foo/') because to be acceptable as
 
61083
 *  a RegExp literal, the text between forward slashes must
 
61084
 *  already match the escaping requirements (e.g. must not contain
 
61085
 *  unescaped forward slashes or be empty).  Escaping IS needed
 
61086
 *  for expressions like 'new Regexp("...", "")' however.
 
61087
 *  Currently, we re-escape in either case.
 
61088
 *
 
61089
 *  Also note that we process the source here in UTF-8 encoded
 
61090
 *  form.  This is correct, because any non-ASCII characters are
 
61091
 *  passed through without change.
 
61092
 */
 
61093
 
 
61094
static void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
 
61095
        duk_context *ctx = (duk_context *) thr;
 
61096
        duk_hstring *h;
 
61097
        duk_hbuffer_dynamic *buf;
 
61098
        const duk_uint8_t *p;
 
61099
        duk_size_t i, n;
 
61100
        duk_uint_fast8_t c_prev, c;
 
61101
 
 
61102
        h = duk_get_hstring(ctx, idx_pattern);
 
61103
        DUK_ASSERT(h != NULL);
 
61104
        p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
 
61105
        n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
 
61106
 
 
61107
        if (n == 0) {
 
61108
                /* return '(?:)' */
 
61109
                duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP);
 
61110
                return;
 
61111
        }
 
61112
 
 
61113
        duk_push_dynamic_buffer(ctx, 0);
 
61114
        buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
61115
        DUK_ASSERT(buf != NULL);
 
61116
 
 
61117
        c_prev = (duk_uint_fast8_t) 0;
 
61118
 
 
61119
        for (i = 0; i < n; i++) {
 
61120
                c = p[i];
 
61121
 
 
61122
                if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
 
61123
                        /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
 
61124
                         * inside a character class, ...) => same escape works.
 
61125
                         */
 
61126
                        duk_hbuffer_append_byte(thr, buf, (duk_uint8_t) '\\');
 
61127
                }
 
61128
                duk_hbuffer_append_byte(thr, buf, (duk_uint8_t) c);
 
61129
 
 
61130
                c_prev = c;
 
61131
        }
 
61132
 
 
61133
        duk_to_string(ctx, -1);  /* -> [ ... escaped_source ] */
 
61134
}
 
61135
 
 
61136
/*
 
61137
 *  Exposed regexp compilation primitive.
 
61138
 *
 
61139
 *  Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
 
61140
 *  actual parsing.  Handles generation of the compiled regexp header and the
 
61141
 *  "boilerplate" capture of the matching substring (save 0 and 1).  Also does some
 
61142
 *  global level regexp checks after recursive compilation has finished.
 
61143
 *
 
61144
 *  An escaped version of the regexp source, suitable for use as a RegExp instance
 
61145
 *  'source' property (see E5 Section 15.10.3), is also left on the stack.
 
61146
 *
 
61147
 *  Input stack:  [ pattern flags ]
 
61148
 *  Output stack: [ bytecode escaped_source ]  (both as strings)
 
61149
 */
 
61150
 
 
61151
void duk_regexp_compile(duk_hthread *thr) {
 
61152
        duk_context *ctx = (duk_context *) thr;
 
61153
        duk_re_compiler_ctx re_ctx;
 
61154
        duk_lexer_point lex_point;
 
61155
        duk_hstring *h_pattern;
 
61156
        duk_hstring *h_flags;
 
61157
        duk_hbuffer_dynamic *h_buffer;
 
61158
        duk__re_disjunction_info ign_disj;
 
61159
 
 
61160
        DUK_ASSERT(thr != NULL);
 
61161
        DUK_ASSERT(ctx != NULL);
 
61162
 
 
61163
        /*
 
61164
         *  Args validation
 
61165
         */
 
61166
 
 
61167
        /* TypeError if fails */
 
61168
        h_pattern = duk_require_hstring(ctx, -2);
 
61169
        h_flags = duk_require_hstring(ctx, -1);
 
61170
 
 
61171
        /*
 
61172
         *  Create normalized 'source' property (E5 Section 15.10.3).
 
61173
         */
 
61174
 
 
61175
        /* [ ... pattern flags ] */
 
61176
 
 
61177
        duk__create_escaped_source(thr, -2);
 
61178
 
 
61179
        /* [ ... pattern flags escaped_source ] */
 
61180
 
 
61181
        /*
 
61182
         *  Init compilation context
 
61183
         */
 
61184
 
 
61185
        duk_push_dynamic_buffer(ctx, 0);
 
61186
        h_buffer = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, -1);
 
61187
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buffer));
 
61188
 
 
61189
        /* [ ... pattern flags escaped_source buffer ] */
 
61190
 
 
61191
        DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
 
61192
        DUK_LEXER_INITCTX(&re_ctx.lex);  /* duplicate zeroing, expect for (possible) NULL inits */
 
61193
        re_ctx.thr = thr;
 
61194
        re_ctx.lex.thr = thr;
 
61195
        re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
 
61196
        re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
 
61197
        re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
 
61198
        re_ctx.buf = h_buffer;
 
61199
        re_ctx.recursion_limit = DUK_RE_COMPILE_RECURSION_LIMIT;
 
61200
        re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
 
61201
 
 
61202
        DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08x, recursion_limit=%d",
 
61203
                    (unsigned int) re_ctx.re_flags, (int) re_ctx.recursion_limit);
 
61204
 
 
61205
        /*
 
61206
         *  Init lexer
 
61207
         */
 
61208
 
 
61209
        lex_point.offset = 0;           /* expensive init, just want to fill window */
 
61210
        lex_point.line = 1;
 
61211
        DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
 
61212
 
 
61213
        /*
 
61214
         *  Compilation
 
61215
         */
 
61216
 
 
61217
        DUK_DPRINT("starting regexp compilation");
 
61218
 
 
61219
        duk__append_u32(&re_ctx, DUK_REOP_SAVE);
 
61220
        duk__append_u32(&re_ctx, 0);
 
61221
        duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
 
61222
        duk__append_u32(&re_ctx, DUK_REOP_SAVE);
 
61223
        duk__append_u32(&re_ctx, 1);
 
61224
        duk__append_u32(&re_ctx, DUK_REOP_MATCH);
 
61225
 
 
61226
        DUK_DPRINT("regexp bytecode size (before header) is %d bytes",
 
61227
                   (int) DUK_HBUFFER_GET_SIZE(re_ctx.buf));
 
61228
 
 
61229
        /*
 
61230
         *  Check for invalid backreferences; note that it is NOT an error
 
61231
         *  to back-reference a capture group which has not yet been introduced
 
61232
         *  in the pattern (as in /\1(foo)/); in fact, the backreference will
 
61233
         *  always match!  It IS an error to back-reference a capture group
 
61234
         *  which will never be introduced in the pattern.  Thus, we can check
 
61235
         *  for such references only after parsing is complete.
 
61236
         */
 
61237
 
 
61238
        if (re_ctx.highest_backref > re_ctx.captures) {
 
61239
                DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "invalid backreference(s)");
 
61240
        }
 
61241
 
 
61242
        /*
 
61243
         *  Emit compiled regexp header: flags, ncaptures
 
61244
         *  (insertion order inverted on purpose)
 
61245
         */
 
61246
 
 
61247
        duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
 
61248
        duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
 
61249
 
 
61250
        DUK_DPRINT("regexp bytecode size (after header) is %d bytes",
 
61251
                   (int) DUK_HBUFFER_GET_SIZE(re_ctx.buf));
 
61252
        DUK_DDDPRINT("compiled regexp: %!xO", re_ctx.buf);
 
61253
 
 
61254
        /* [ ... pattern flags escaped_source buffer ] */
 
61255
 
 
61256
        duk_to_string(ctx, -1);  /* coerce to string */
 
61257
 
 
61258
        /* [ ... pattern flags escaped_source bytecode ] */
 
61259
 
 
61260
        /*
 
61261
         *  Finalize stack
 
61262
         */
 
61263
 
 
61264
        duk_remove(ctx, -4);     /* -> [ ... flags escaped_source bytecode ] */
 
61265
        duk_remove(ctx, -3);     /* -> [ ... escaped_source bytecode ] */
 
61266
 
 
61267
        DUK_DPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
 
61268
                   duk_get_tval(ctx, -1), duk_get_tval(ctx, -2));
 
61269
}
 
61270
 
 
61271
/*
 
61272
 *  Create a RegExp instance (E5 Section 15.10.7).
 
61273
 *
 
61274
 *  Note: the output stack left by duk_regexp_compile() is directly compatible
 
61275
 *  with the input here.
 
61276
 *
 
61277
 *  Input stack:  [ escaped_source bytecode ]  (both as strings)
 
61278
 *  Output stack: [ RegExp ]
 
61279
 */
 
61280
 
 
61281
void duk_regexp_create_instance(duk_hthread *thr) {
 
61282
        duk_context *ctx = (duk_context *) thr;
 
61283
        duk_hobject *h;
 
61284
        duk_hstring *h_bc;
 
61285
        duk_small_int_t re_flags;
 
61286
 
 
61287
        /* [ ... escape_source bytecode ] */
 
61288
 
 
61289
        h_bc = duk_get_hstring(ctx, -1);
 
61290
        DUK_ASSERT(h_bc != NULL);
 
61291
        DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);          /* always at least the header */
 
61292
        DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
 
61293
        DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);  /* flags always encodes to 1 byte */
 
61294
        re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
 
61295
 
 
61296
        /* [ ... escaped_source bytecode ] */
 
61297
 
 
61298
        duk_push_object(ctx);
 
61299
        h = duk_get_hobject(ctx, -1);
 
61300
        DUK_ASSERT(h != NULL);
 
61301
        duk_insert(ctx, -3);
 
61302
 
 
61303
        /* [ ... regexp_object escaped_source bytecode ] */
 
61304
 
 
61305
        DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
 
61306
        DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
 
61307
 
 
61308
        duk_def_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
 
61309
 
 
61310
        /* [ ... regexp_object escaped_source ] */
 
61311
 
 
61312
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE);
 
61313
 
 
61314
        /* [ ... regexp_object ] */
 
61315
 
 
61316
        duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
 
61317
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE);
 
61318
 
 
61319
        duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
 
61320
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE);
 
61321
 
 
61322
        duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
 
61323
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE);
 
61324
 
 
61325
        duk_push_int(ctx, 0);
 
61326
        duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
 
61327
 
 
61328
        /* [ ... regexp_object ] */
 
61329
}
 
61330
 
 
61331
#undef DUK__BUFLEN
 
61332
 
 
61333
#else  /* DUK_USE_REGEXP_SUPPORT */
 
61334
 
 
61335
/* regexp support disabled */
 
61336
 
 
61337
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
61338
 
 
61339
#line 1 "duk_regexp_executor.c"
 
61340
/*
 
61341
 *  Regexp executor.
 
61342
 *
 
61343
 *  Safety: the Ecmascript executor should prevent user from reading and
 
61344
 *  replacing regexp bytecode.  Even so, the executor must validate all
 
61345
 *  memory accesses etc.  When an invalid access is detected (e.g. a 'save'
 
61346
 *  opcode to invalid, unallocated index) it should fail with an internal
 
61347
 *  error but not cause a segmentation fault.
 
61348
 *
 
61349
 *  Notes:
 
61350
 *
 
61351
 *    - Backtrack counts are limited to unsigned 32 bits but should
 
61352
 *      technically be duk_size_t for strings longer than 4G chars.
 
61353
 *      This also requires a regexp bytecode change.
 
61354
 */
 
61355
 
 
61356
/* include removed: duk_internal.h */
 
61357
 
 
61358
#ifdef DUK_USE_REGEXP_SUPPORT
 
61359
 
 
61360
/*
 
61361
 *  Helpers for UTF-8 handling
 
61362
 *
 
61363
 *  For bytecode readers the duk_uint32_t and duk_int32_t types are correct
 
61364
 *  because they're used for more than just codepoints.
 
61365
 */
 
61366
 
 
61367
static duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, duk_uint8_t **pc) {
 
61368
        return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
 
61369
}
 
61370
 
 
61371
static duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, duk_uint8_t **pc) {
 
61372
        duk_uint32_t t;
 
61373
 
 
61374
        /* signed integer encoding needed to work with UTF-8 */
 
61375
        t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
 
61376
        if (t & 1) {
 
61377
                return -(t >> 1);
 
61378
        } else {
 
61379
                return (t >> 1);
 
61380
        }
 
61381
}
 
61382
 
 
61383
static duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
 
61384
        duk_uint8_t *p;
 
61385
 
 
61386
        /* Note: allow backtracking from p == ptr_end */
 
61387
        p = *ptr;
 
61388
        if (p < ptr_start || p > ptr_end) {
 
61389
                goto fail;
 
61390
        }
 
61391
 
 
61392
        while (count > 0) {
 
61393
                for (;;) {
 
61394
                        p--;
 
61395
                        if (p < ptr_start) {
 
61396
                                goto fail;
 
61397
                        }
 
61398
                        if ((*p & 0xc0) != 0x80) {
 
61399
                                /* utf-8 continuation bytes have the form 10xx xxxx */
 
61400
                                break;
 
61401
                        }
 
61402
                }
 
61403
                count--;
 
61404
        }
 
61405
        *ptr = p;
 
61406
        return p;
 
61407
 
 
61408
 fail:
 
61409
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "regexp backtrack failed");
 
61410
        return NULL;  /* never here */
 
61411
}
 
61412
 
 
61413
static duk_uint8_t *duk__utf8_advance(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
 
61414
        duk_uint8_t *p;
 
61415
 
 
61416
        p = *ptr;
 
61417
        if (p < ptr_start || p >= ptr_end) {
 
61418
                goto fail;
 
61419
        }
 
61420
 
 
61421
        while (count > 0) {
 
61422
                for (;;) {
 
61423
                        p++;
 
61424
 
 
61425
                        /* Note: if encoding ends by hitting end of input, we don't check that
 
61426
                         * the encoding is valid, we just assume it is.
 
61427
                         */
 
61428
                        if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
 
61429
                                /* utf-8 continuation bytes have the form 10xx xxxx */
 
61430
                                break;
 
61431
                        }
 
61432
                }
 
61433
                count--;
 
61434
        }
 
61435
 
 
61436
        *ptr = p;
 
61437
        return p;
 
61438
 
 
61439
 fail:
 
61440
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "regexp advance failed");
 
61441
        return NULL;  /* never here */
 
61442
}
 
61443
 
 
61444
/*
 
61445
 *  Helpers for dealing with the input string
 
61446
 */
 
61447
 
 
61448
/* Get a (possibly canonicalized) input character from current sp.  The input
 
61449
 * itself is never modified, and captures always record non-canonicalized
 
61450
 * characters even in case-insensitive matching.
 
61451
 */
 
61452
static duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, duk_uint8_t **sp) {
 
61453
        duk_codepoint_t res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
 
61454
        if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
 
61455
                res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
 
61456
        }
 
61457
        return res;
 
61458
}
 
61459
 
 
61460
static duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, duk_uint8_t **sp, duk_uint_fast32_t count) {
 
61461
        return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
 
61462
}
 
61463
 
 
61464
/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
 
61465
static duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, duk_uint8_t *sp) {
 
61466
        /* note: caller 'sp' is intentionally not updated here */
 
61467
        (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
 
61468
        return duk__inp_get_cp(re_ctx, &sp);
 
61469
}
 
61470
        
 
61471
/*
 
61472
 *  Regexp recursive matching function.
 
61473
 *
 
61474
 *  Returns 'sp' on successful match (points to character after last matched one),
 
61475
 *  NULL otherwise.
 
61476
 *
 
61477
 *  The C recursion depth limit check is only performed in this function, this
 
61478
 *  suffices because the function is present in all true recursion required by
 
61479
 *  regexp execution.
 
61480
 */
 
61481
 
 
61482
static duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, duk_uint8_t *pc, duk_uint8_t *sp) {
 
61483
        if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
 
61484
                DUK_ERROR(re_ctx->thr, DUK_ERR_RANGE_ERROR, "regexp executor recursion limit");
 
61485
        }
 
61486
        re_ctx->recursion_depth++;
 
61487
 
 
61488
        for (;;) {
 
61489
                duk_small_int_t op;
 
61490
 
 
61491
                if (re_ctx->steps_count >= re_ctx->steps_limit) {
 
61492
                        DUK_ERROR(re_ctx->thr, DUK_ERR_RANGE_ERROR, "regexp step limit");
 
61493
                }
 
61494
                re_ctx->steps_count++;
 
61495
 
 
61496
                op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
 
61497
 
 
61498
                DUK_DDDPRINT("match: rec=%d, steps=%d, pc (after op)=%d, sp=%d, op=%d",
 
61499
                             (int) re_ctx->recursion_depth,
 
61500
                             (int) re_ctx->steps_count,
 
61501
                             (int) (pc - re_ctx->bytecode),
 
61502
                             (int) (sp - re_ctx->input),
 
61503
                             (int) op);
 
61504
 
 
61505
                switch (op) {
 
61506
                case DUK_REOP_MATCH: {
 
61507
                        goto match;
 
61508
                }
 
61509
                case DUK_REOP_CHAR: {
 
61510
                        /*
 
61511
                         *  Byte-based matching would be possible for case-sensitive
 
61512
                         *  matching but not for case-insensitive matching.  So, we
 
61513
                         *  match by decoding the input and bytecode character normally.
 
61514
                         *
 
61515
                         *  Bytecode characters are assumed to be already canonicalized.
 
61516
                         *  Input characters are canonicalized automatically by
 
61517
                         *  duk__inp_get_cp() if necessary.
 
61518
                         *
 
61519
                         *  There is no opcode for matching multiple characters.  The
 
61520
                         *  regexp compiler has trouble joining strings efficiently
 
61521
                         *  during compilation.  See doc/regexp.txt for more discussion.
 
61522
                         */
 
61523
                        duk_codepoint_t c1, c2;
 
61524
 
 
61525
                        c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
 
61526
                        DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
 
61527
                                   c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1));  /* canonicalized by compiler */
 
61528
                        if (sp >= re_ctx->input_end) {
 
61529
                                goto fail;
 
61530
                        }
 
61531
                        c2 = duk__inp_get_cp(re_ctx, &sp);
 
61532
                        DUK_DDDPRINT("char match, c1=%d, c2=%d", (int) c1, (int) c2);
 
61533
                        if (c1 != c2) {
 
61534
                                goto fail;
 
61535
                        }
 
61536
                        break;
 
61537
                }
 
61538
                case DUK_REOP_PERIOD: {
 
61539
                        duk_codepoint_t c;
 
61540
 
 
61541
                        if (sp >= re_ctx->input_end) {
 
61542
                                goto fail;
 
61543
                        }
 
61544
                        c = duk__inp_get_cp(re_ctx, &sp);
 
61545
                        if (duk_unicode_is_line_terminator(c)) {
 
61546
                                /* E5 Sections 15.10.2.8, 7.3 */
 
61547
                                goto fail;
 
61548
                        }
 
61549
                        break;
 
61550
                }
 
61551
                case DUK_REOP_RANGES:
 
61552
                case DUK_REOP_INVRANGES: {
 
61553
                        duk_uint32_t n;
 
61554
                        duk_codepoint_t c;
 
61555
                        duk_small_int_t match;
 
61556
        
 
61557
                        n = duk__bc_get_u32(re_ctx, &pc);
 
61558
                        if (sp >= re_ctx->input_end) {
 
61559
                                goto fail;
 
61560
                        }
 
61561
                        c = duk__inp_get_cp(re_ctx, &sp);
 
61562
 
 
61563
                        match = 0;
 
61564
                        while (n) {
 
61565
                                duk_codepoint_t r1, r2;
 
61566
                                r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
 
61567
                                r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
 
61568
                                DUK_DDDPRINT("matching ranges/invranges, n=%d, r1=%d, r2=%d, c=%d",
 
61569
                                             (int) n, (int) r1, (int) r2, (int) c);
 
61570
                                if (c >= r1 && c <= r2) {
 
61571
                                        /* Note: don't bail out early, we must read all the ranges from
 
61572
                                         * bytecode.  Another option is to skip them efficiently after
 
61573
                                         * breaking out of here.  Prefer smallest code.
 
61574
                                         */
 
61575
                                        match = 1;
 
61576
                                }
 
61577
                                n--;
 
61578
                        }
 
61579
 
 
61580
                        if (op == DUK_REOP_RANGES) {
 
61581
                                if (!match) {
 
61582
                                        goto fail;
 
61583
                                }
 
61584
                        } else {
 
61585
                                DUK_ASSERT(op == DUK_REOP_INVRANGES);
 
61586
                                if (match) {
 
61587
                                        goto fail;
 
61588
                                }
 
61589
                        }
 
61590
                        break;
 
61591
                }
 
61592
                case DUK_REOP_ASSERT_START: {
 
61593
                        duk_codepoint_t c;
 
61594
 
 
61595
                        if (sp <= re_ctx->input) {
 
61596
                                break;
 
61597
                        }
 
61598
                        if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
 
61599
                                goto fail;
 
61600
                        }
 
61601
                        c = duk__inp_get_prev_cp(re_ctx, sp);
 
61602
                        if (duk_unicode_is_line_terminator(c)) {
 
61603
                                /* E5 Sections 15.10.2.8, 7.3 */
 
61604
                                break;
 
61605
                        }
 
61606
                        goto fail;
 
61607
                }
 
61608
                case DUK_REOP_ASSERT_END: {
 
61609
                        duk_codepoint_t c;
 
61610
                        duk_uint8_t *temp_sp;
 
61611
 
 
61612
                        if (sp >= re_ctx->input_end) {
 
61613
                                break;
 
61614
                        }
 
61615
                        if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
 
61616
                                goto fail;
 
61617
                        }
 
61618
                        temp_sp = sp;
 
61619
                        c = duk__inp_get_cp(re_ctx, &temp_sp);
 
61620
                        if (duk_unicode_is_line_terminator(c)) {
 
61621
                                /* E5 Sections 15.10.2.8, 7.3 */
 
61622
                                break;
 
61623
                        }
 
61624
                        goto fail;
 
61625
                }
 
61626
                case DUK_REOP_ASSERT_WORD_BOUNDARY:
 
61627
                case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
 
61628
                        /*
 
61629
                         *  E5 Section 15.10.2.6.  The previous and current character
 
61630
                         *  should -not- be canonicalized as they are now.  However,
 
61631
                         *  canonicalization does not affect the result of IsWordChar()
 
61632
                         *  (which depends on Unicode characters never canonicalizing
 
61633
                         *  into ASCII characters) so this does not matter.
 
61634
                         */
 
61635
                        duk_small_int_t w1, w2;
 
61636
 
 
61637
                        if (sp <= re_ctx->input) {
 
61638
                                w1 = 0;  /* not a wordchar */
 
61639
                        } else {
 
61640
                                duk_codepoint_t c;
 
61641
                                c = duk__inp_get_prev_cp(re_ctx, sp);
 
61642
                                w1 = duk_unicode_re_is_wordchar(c);
 
61643
                        }
 
61644
                        if (sp >= re_ctx->input_end) {
 
61645
                                w2 = 0;  /* not a wordchar */
 
61646
                        } else {
 
61647
                                duk_uint8_t *tmp_sp = sp;  /* dummy so sp won't get updated */
 
61648
                                duk_codepoint_t c;
 
61649
                                c = duk__inp_get_cp(re_ctx, &tmp_sp);
 
61650
                                w2 = duk_unicode_re_is_wordchar(c);
 
61651
                        }
 
61652
 
 
61653
                        if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
 
61654
                                if (w1 == w2) {
 
61655
                                        goto fail;
 
61656
                                }
 
61657
                        } else {
 
61658
                                DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
 
61659
                                if (w1 != w2) {
 
61660
                                        goto fail;
 
61661
                                }
 
61662
                        }
 
61663
                        break;
 
61664
                }
 
61665
                case DUK_REOP_JUMP: {
 
61666
                        duk_int32_t skip;
 
61667
 
 
61668
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61669
                        pc += skip;
 
61670
                        break;
 
61671
                }
 
61672
                case DUK_REOP_SPLIT1: {
 
61673
                        /* split1: prefer direct execution (no jump) */
 
61674
                        duk_uint8_t *sub_sp;
 
61675
                        duk_int32_t skip;
 
61676
 
 
61677
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61678
                        sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61679
                        if (sub_sp) {
 
61680
                                sp = sub_sp;
 
61681
                                goto match;
 
61682
                        }
 
61683
                        pc += skip;
 
61684
                        break;
 
61685
                }
 
61686
                case DUK_REOP_SPLIT2: {
 
61687
                        /* split2: prefer jump execution (not direct) */
 
61688
                        duk_uint8_t *sub_sp;
 
61689
                        duk_int32_t skip;
 
61690
 
 
61691
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61692
                        sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
 
61693
                        if (sub_sp) {
 
61694
                                sp = sub_sp;
 
61695
                                goto match;
 
61696
                        }
 
61697
                        break;
 
61698
                }
 
61699
                case DUK_REOP_SQMINIMAL: {
 
61700
                        duk_uint32_t q, qmin, qmax;
 
61701
                        duk_int32_t skip;
 
61702
                        duk_uint8_t *sub_sp;
 
61703
 
 
61704
                        qmin = duk__bc_get_u32(re_ctx, &pc);
 
61705
                        qmax = duk__bc_get_u32(re_ctx, &pc);
 
61706
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61707
                        DUK_DDDPRINT("minimal quantifier, qmin=%u, qmax=%u, skip=%d",
 
61708
                                     (unsigned int) qmin, (unsigned int) qmax, (int) skip);
 
61709
 
 
61710
                        q = 0;
 
61711
                        while (q <= qmax) {
 
61712
                                if (q >= qmin) {
 
61713
                                        sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
 
61714
                                        if (sub_sp) {
 
61715
                                                sp = sub_sp;
 
61716
                                                goto match;
 
61717
                                        }
 
61718
                                }
 
61719
                                sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61720
                                if (!sub_sp) {
 
61721
                                        break;
 
61722
                                }
 
61723
                                sp = sub_sp;
 
61724
                                q++;
 
61725
                        }
 
61726
                        goto fail;
 
61727
                }
 
61728
                case DUK_REOP_SQGREEDY: {
 
61729
                        duk_uint32_t q, qmin, qmax, atomlen;
 
61730
                        duk_int32_t skip;
 
61731
                        duk_uint8_t *sub_sp;
 
61732
 
 
61733
                        qmin = duk__bc_get_u32(re_ctx, &pc);
 
61734
                        qmax = duk__bc_get_u32(re_ctx, &pc);
 
61735
                        atomlen = duk__bc_get_u32(re_ctx, &pc);
 
61736
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61737
                        DUK_DDDPRINT("greedy quantifier, qmin=%u, qmax=%u, atomlen=%u, skip=%d",
 
61738
                                     (unsigned int) qmin, (unsigned int) qmax, (unsigned int) atomlen, (int) skip);
 
61739
 
 
61740
                        q = 0;
 
61741
                        while (q < qmax) {
 
61742
                                sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61743
                                if (!sub_sp) {
 
61744
                                        break;
 
61745
                                }
 
61746
                                sp = sub_sp;
 
61747
                                q++;
 
61748
                        }
 
61749
                        while (q >= qmin) {
 
61750
                                sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
 
61751
                                if (sub_sp) {
 
61752
                                        sp = sub_sp;
 
61753
                                        goto match;
 
61754
                                }
 
61755
                                if (q == qmin) {
 
61756
                                        break;
 
61757
                                }
 
61758
 
 
61759
                                /* Note: if atom were to contain e.g. captures, we would need to
 
61760
                                 * re-match the atom to get correct captures.  Simply quantifiers
 
61761
                                 * do not allow captures in their atom now, so this is not an issue.
 
61762
                                 */
 
61763
 
 
61764
                                DUK_DDDPRINT("greedy quantifier, backtrack %d characters (atomlen)",
 
61765
                                             atomlen);
 
61766
                                sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
 
61767
                                q--;
 
61768
                        }
 
61769
                        goto fail;
 
61770
                }
 
61771
                case DUK_REOP_SAVE: {
 
61772
                        duk_uint32_t idx;
 
61773
                        duk_uint8_t *old;
 
61774
                        duk_uint8_t *sub_sp;
 
61775
 
 
61776
                        idx = duk__bc_get_u32(re_ctx, &pc);
 
61777
                        if (idx >= re_ctx->nsaved) {
 
61778
                                /* idx is unsigned, < 0 check is not necessary */
 
61779
                                DUK_DPRINT("internal error, regexp save index insane: idx=%d", (int) idx);
 
61780
                                goto internal_error;
 
61781
                        }
 
61782
                        old = re_ctx->saved[idx];
 
61783
                        re_ctx->saved[idx] = sp;
 
61784
                        sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61785
                        if (sub_sp) {
 
61786
                                sp = sub_sp;
 
61787
                                goto match;
 
61788
                        }
 
61789
                        re_ctx->saved[idx] = old;
 
61790
                        goto fail;
 
61791
                }
 
61792
                case DUK_REOP_WIPERANGE: {
 
61793
                        /* Wipe capture range and save old values for backtracking.
 
61794
                         *
 
61795
                         * XXX: this typically happens with a relatively small idx_count.
 
61796
                         * It might be useful to handle cases where the count is small
 
61797
                         * (say <= 8) by saving the values in stack instead.  This would
 
61798
                         * reduce memory churn and improve performance, at the cost of a
 
61799
                         * slightly higher code footprint.
 
61800
                         */
 
61801
                        duk_uint32_t idx_start, idx_count;
 
61802
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
61803
                        duk_uint32_t idx_end, idx;
 
61804
#endif
 
61805
                        duk_uint8_t **range_save;
 
61806
                        duk_uint8_t *sub_sp;
 
61807
 
 
61808
                        idx_start = duk__bc_get_u32(re_ctx, &pc);
 
61809
                        idx_count = duk__bc_get_u32(re_ctx, &pc);
 
61810
                        DUK_DDDPRINT("wipe saved range: start=%d, count=%d -> [%d,%d] (captures [%d,%d])",
 
61811
                                     idx_start, idx_count,
 
61812
                                     idx_start, idx_start + idx_count - 1,
 
61813
                                     idx_start / 2, (idx_start + idx_count - 1) / 2);
 
61814
                        if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
 
61815
                                /* idx is unsigned, < 0 check is not necessary */
 
61816
                                DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%d, idx_count=%d",
 
61817
                                           (int) idx_start, (int) idx_count);
 
61818
                                goto internal_error;
 
61819
                        }
 
61820
                        DUK_ASSERT(idx_count > 0);
 
61821
 
 
61822
                        duk_require_stack((duk_context *) re_ctx->thr, 1);
 
61823
                        range_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
 
61824
                                                                            sizeof(duk_uint8_t *) * idx_count);
 
61825
                        DUK_ASSERT(range_save != NULL);
 
61826
                        DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
 
61827
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
61828
                        idx_end = idx_start + idx_count;
 
61829
                        for (idx = idx_start; idx < idx_end; idx++) {
 
61830
                                re_ctx->saved[idx] = NULL;
 
61831
                        }
 
61832
#else
 
61833
                        DUK_MEMZERO(re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
 
61834
#endif
 
61835
 
 
61836
                        sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61837
                        if (sub_sp) {
 
61838
                                /* match: keep wiped/resaved values */
 
61839
                                DUK_DDDPRINT("match: keep wiped/resaved values [%d,%d] (captures [%d,%d])",
 
61840
                                             (int) idx_start, (int) (idx_start + idx_count - 1),
 
61841
                                             idx_start / 2, (idx_start + idx_count - 1) / 2);
 
61842
                                duk_pop((duk_context *) re_ctx->thr);
 
61843
                                sp = sub_sp;
 
61844
                                goto match;
 
61845
                        }
 
61846
 
 
61847
                        /* fail: restore saves */
 
61848
                        DUK_DDDPRINT("fail: restore wiped/resaved values [%d,%d] (captures [%d,%d])",
 
61849
                                     (int) idx_start, (int) (idx_start + idx_count - 1),
 
61850
                                     idx_start / 2, (idx_start + idx_count - 1) / 2);
 
61851
                        DUK_MEMCPY(re_ctx->saved + idx_start, range_save, sizeof(duk_uint8_t *) * idx_count);
 
61852
                        duk_pop((duk_context *) re_ctx->thr);
 
61853
                        goto fail;
 
61854
                }
 
61855
                case DUK_REOP_LOOKPOS:
 
61856
                case DUK_REOP_LOOKNEG: {
 
61857
                        /*
 
61858
                         *  Needs a save of multiple saved[] entries depending on what range
 
61859
                         *  may be overwritten.  Because the regexp parser does no such analysis,
 
61860
                         *  we currently save the entire saved array here.  Lookaheads are thus
 
61861
                         *  a bit expensive.  Note that the saved array is not needed for just
 
61862
                         *  the lookahead sub-match, but for the matching of the entire sequel.
 
61863
                         *
 
61864
                         *  The temporary save buffer is pushed on to the valstack to handle
 
61865
                         *  errors correctly.  Each lookahead causes a C recursion and pushes
 
61866
                         *  more stuff on the value stack.  If the C recursion limit is less
 
61867
                         *  than the value stack spare, there is no need to check the stack.
 
61868
                         *  We do so regardless, just in case.
 
61869
                         */
 
61870
 
 
61871
                        duk_int32_t skip;
 
61872
                        duk_uint8_t **full_save;
 
61873
                        duk_uint8_t *sub_sp;
 
61874
 
 
61875
                        DUK_ASSERT(re_ctx->nsaved > 0);
 
61876
 
 
61877
                        duk_require_stack((duk_context *) re_ctx->thr, 1);
 
61878
                        full_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
 
61879
                                                                           sizeof(duk_uint8_t *) * re_ctx->nsaved);
 
61880
                        DUK_ASSERT(full_save != NULL);
 
61881
                        DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
 
61882
 
 
61883
                        skip = duk__bc_get_i32(re_ctx, &pc);
 
61884
                        sub_sp = duk__match_regexp(re_ctx, pc, sp);
 
61885
                        if (op == DUK_REOP_LOOKPOS) {
 
61886
                                if (!sub_sp) {
 
61887
                                        goto lookahead_fail;
 
61888
                                }
 
61889
                        } else {
 
61890
                                if (sub_sp) {
 
61891
                                        goto lookahead_fail;
 
61892
                                }
 
61893
                        }
 
61894
                        sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
 
61895
                        if (sub_sp) {
 
61896
                                /* match: keep saves */
 
61897
                                duk_pop((duk_context *) re_ctx->thr);
 
61898
                                sp = sub_sp;
 
61899
                                goto match;
 
61900
                        }
 
61901
 
 
61902
                        /* fall through */
 
61903
 
 
61904
                 lookahead_fail:
 
61905
                        /* fail: restore saves */
 
61906
                        DUK_MEMCPY(re_ctx->saved, full_save, sizeof(duk_uint8_t *) * re_ctx->nsaved);
 
61907
                        duk_pop((duk_context *) re_ctx->thr);
 
61908
                        goto fail;
 
61909
                }
 
61910
                case DUK_REOP_BACKREFERENCE: {
 
61911
                        /*
 
61912
                         *  Byte matching for back-references would be OK in case-
 
61913
                         *  sensitive matching.  In case-insensitive matching we need
 
61914
                         *  to canonicalize characters, so back-reference matching needs
 
61915
                         *  to be done with codepoints instead.  So, we just decode
 
61916
                         *  everything normally here, too.
 
61917
                         *
 
61918
                         *  Note: back-reference index which is 0 or higher than
 
61919
                         *  NCapturingParens (= number of capturing parens in the
 
61920
                         *  -entire- regexp) is a compile time error.  However, a
 
61921
                         *  backreference referring to a valid capture which has
 
61922
                         *  not matched anything always succeeds!  See E5 Section
 
61923
                         *  15.10.2.9, step 5, sub-step 3.
 
61924
                         */
 
61925
                        duk_uint32_t idx;
 
61926
                        duk_uint8_t *p;
 
61927
 
 
61928
                        idx = duk__bc_get_u32(re_ctx, &pc);
 
61929
                        idx = idx << 1;         /* backref n -> saved indices [n*2, n*2+1] */
 
61930
                        if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
 
61931
                                /* regexp compiler should catch these */
 
61932
                                DUK_DPRINT("internal error, backreference index insane");
 
61933
                                goto internal_error;
 
61934
                        }
 
61935
                        if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
 
61936
                                /* capture is 'undefined', always matches! */
 
61937
                                DUK_DDDPRINT("backreference: saved[%d,%d] not complete, always match",
 
61938
                                             idx, idx+1);
 
61939
                                break;
 
61940
                        }
 
61941
                        DUK_DDDPRINT("backreference: match saved[%d,%d]", idx, idx+1);
 
61942
 
 
61943
                        p = re_ctx->saved[idx];
 
61944
                        while (p < re_ctx->saved[idx+1]) {
 
61945
                                duk_codepoint_t c1, c2;
 
61946
 
 
61947
                                /* Note: not necessary to check p against re_ctx->input_end:
 
61948
                                 * the memory access is checked by duk__inp_get_cp(), while
 
61949
                                 * valid compiled regexps cannot write a saved[] entry
 
61950
                                 * which points to outside the string.
 
61951
                                 */
 
61952
                                if (sp >= re_ctx->input_end) {
 
61953
                                        goto fail;
 
61954
                                }
 
61955
                                c1 = duk__inp_get_cp(re_ctx, &p);
 
61956
                                c2 = duk__inp_get_cp(re_ctx, &sp);
 
61957
                                if (c1 != c2) {
 
61958
                                        goto fail;
 
61959
                                }
 
61960
                        }
 
61961
                        break;
 
61962
                }
 
61963
                default: {
 
61964
                        DUK_DPRINT("internal error, regexp opcode error: %d", op);
 
61965
                        goto internal_error;
 
61966
                }
 
61967
                }
 
61968
        }
 
61969
 
 
61970
 match:
 
61971
        re_ctx->recursion_depth--;
 
61972
        return sp;
 
61973
 
 
61974
 fail:
 
61975
        re_ctx->recursion_depth--;
 
61976
        return NULL;
 
61977
 
 
61978
 internal_error:
 
61979
        DUK_ERROR(re_ctx->thr, DUK_ERR_INTERNAL_ERROR, "regexp internal error");
 
61980
        return NULL;  /* never here */
 
61981
}
 
61982
 
 
61983
/*
 
61984
 *  Exposed matcher function which provides the semantics of RegExp.prototype.exec().
 
61985
 *
 
61986
 *  RegExp.prototype.test() has the same semantics as exec() but does not return the
 
61987
 *  result object (which contains the matching string and capture groups).  Currently
 
61988
 *  there is no separate test() helper, so a temporary result object is created and
 
61989
 *  discarded if test() is needed.  This is intentional, to save code space.
 
61990
 *
 
61991
 *  Input stack:  [ ... re_obj input ]
 
61992
 *  Output stack: [ ... result ]
 
61993
 */
 
61994
 
 
61995
static void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
 
61996
        duk_context *ctx = (duk_context *) thr;
 
61997
        duk_re_matcher_ctx re_ctx;
 
61998
        duk_hobject *h_regexp;
 
61999
        duk_hstring *h_bytecode;
 
62000
        duk_hstring *h_input;
 
62001
        duk_uint8_t *pc;
 
62002
        duk_uint8_t *sp;
 
62003
        duk_small_int_t match = 0;
 
62004
        duk_small_int_t global;
 
62005
        duk_uint_fast32_t i;
 
62006
        double d;
 
62007
        duk_uint32_t char_offset;
 
62008
 
 
62009
        DUK_ASSERT(thr != NULL);
 
62010
        DUK_ASSERT(ctx != NULL);
 
62011
 
 
62012
        DUK_DDPRINT("regexp match: regexp=%!T, input=%!T", duk_get_tval(ctx, -2), duk_get_tval(ctx, -1));
 
62013
 
 
62014
        /*
 
62015
         *  Regexp instance check, bytecode check, input coercion.
 
62016
         *
 
62017
         *  See E5 Section 15.10.6.
 
62018
         */
 
62019
 
 
62020
        /* TypeError if wrong; class check, see E5 Section 15.10.6 */
 
62021
        h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
 
62022
        DUK_ASSERT(h_regexp != NULL);
 
62023
        DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
 
62024
        DUK_UNREF(h_regexp);
 
62025
 
 
62026
        duk_to_string(ctx, -1);
 
62027
        h_input = duk_get_hstring(ctx, -1);
 
62028
        DUK_ASSERT(h_input != NULL);
 
62029
 
 
62030
        duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_BYTECODE);  /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
 
62031
        h_bytecode = duk_require_hstring(ctx, -1);  /* no regexp instance should exist without a non-configurable bytecode property */
 
62032
        DUK_ASSERT(h_bytecode != NULL);
 
62033
 
 
62034
        /*
 
62035
         *  Basic context initialization.
 
62036
         *
 
62037
         *  Some init values are read from the bytecode header
 
62038
         *  whose format is (UTF-8 codepoints):
 
62039
         *
 
62040
         *    uint   flags
 
62041
         *    uint   nsaved (even, 2n+2 where n = num captures)
 
62042
         */
 
62043
 
 
62044
        /* [ ... re_obj input bc ] */
 
62045
 
 
62046
        DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
 
62047
 
 
62048
        re_ctx.thr = thr;
 
62049
        re_ctx.input = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
 
62050
        re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
 
62051
        re_ctx.bytecode = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
 
62052
        re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
 
62053
        re_ctx.saved = NULL;
 
62054
        re_ctx.recursion_limit = DUK_RE_EXECUTE_RECURSION_LIMIT;
 
62055
        re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
 
62056
 
 
62057
        /* read header */
 
62058
        pc = re_ctx.bytecode;
 
62059
        re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
 
62060
        re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
 
62061
        re_ctx.bytecode = pc;
 
62062
 
 
62063
        DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL);  /* must fit into duk_small_int_t */
 
62064
        global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
 
62065
 
 
62066
        DUK_ASSERT(re_ctx.nsaved >= 2);
 
62067
        DUK_ASSERT((re_ctx.nsaved % 2) == 0);
 
62068
 
 
62069
        duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
 
62070
        re_ctx.saved = (duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
 
62071
        DUK_ASSERT(re_ctx.saved != NULL);
 
62072
 
 
62073
        /* [ ... re_obj input bc saved_buf ] */
 
62074
 
 
62075
        /* buffer is automatically zeroed */
 
62076
#ifdef DUK_USE_EXPLICIT_NULL_INIT
 
62077
        for (i = 0; i < re_ctx.nsaved; i++) {
 
62078
                re_ctx.saved[i] = (duk_uint8_t *) NULL;
 
62079
        }
 
62080
#endif
 
62081
 
 
62082
        DUK_DDDPRINT("regexp ctx initialized, flags=0x%08x, nsaved=%d, recursion_limit=%d, steps_limit=%d",
 
62083
                     (unsigned int) re_ctx.re_flags, (int) re_ctx.nsaved, (int) re_ctx.recursion_limit,
 
62084
                     (int) re_ctx.steps_limit);
 
62085
 
 
62086
        /*
 
62087
         *  Get starting character offset for match, and initialize 'sp' based on it.
 
62088
         *
 
62089
         *  Note: lastIndex is non-configurable so it must be present (we check the
 
62090
         *  internal class of the object above, so we know it is).  User code can set
 
62091
         *  its value to an arbitrary (garbage) value though; E5 requires that lastIndex
 
62092
         *  be coerced to a number before using.  The code below works even if the
 
62093
         *  property is missing: the value will then be coerced to zero.
 
62094
         *
 
62095
         *  Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
 
62096
         *  For instance, ToInteger(+Infinity) = +Infinity.  We track the match offset
 
62097
         *  as an integer, but pre-check it to be inside the 32-bit range before the loop.
 
62098
         *  If not, the check in E5 Section 15.10.6.2, step 9.a applies.
 
62099
         */
 
62100
 
 
62101
        /* XXX: lastIndex handling produces a lot of asm */
 
62102
 
 
62103
        /* [ ... re_obj input bc saved_buf ] */
 
62104
 
 
62105
        duk_get_prop_stridx(ctx, -4, DUK_STRIDX_LAST_INDEX);  /* -> [ ... re_obj input bc saved_buf lastIndex ] */
 
62106
        (void) duk_to_int(ctx, -1);  /* ToInteger(lastIndex) */
 
62107
        d = duk_get_number(ctx, -1);  /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
 
62108
        duk_pop(ctx);
 
62109
 
 
62110
        if (global) {
 
62111
                if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
 
62112
                        /* match fail */
 
62113
                        char_offset = 0;   /* not really necessary */
 
62114
                        DUK_ASSERT(match == 0);
 
62115
                        goto match_over;
 
62116
                }
 
62117
                char_offset = (duk_uint32_t) d;
 
62118
        } else {
 
62119
                /* lastIndex must be ignored for non-global regexps, but get the
 
62120
                 * value for (theoretical) side effects.  No side effects can
 
62121
                 * really occur, because lastIndex is a normal property and is
 
62122
                 * always non-configurable for RegExp instances.
 
62123
                 */
 
62124
                char_offset = (duk_uint32_t) 0;
 
62125
        }
 
62126
 
 
62127
        sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
 
62128
 
 
62129
        /*
 
62130
         *  Match loop.
 
62131
         *
 
62132
         *  Try matching at different offsets until match found or input exhausted.
 
62133
         */
 
62134
 
 
62135
        /* [ ... re_obj input bc saved_buf ] */
 
62136
 
 
62137
        DUK_ASSERT(match == 0);
 
62138
 
 
62139
        for (;;) {
 
62140
                /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
 
62141
                DUK_ASSERT_DISABLE(char_offset >= 0);
 
62142
                DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
 
62143
 
 
62144
                /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
 
62145
                DUK_ASSERT(re_ctx.recursion_depth == 0);
 
62146
 
 
62147
                DUK_DDDPRINT("attempt match at char offset %d; %p [%p,%p]",
 
62148
                             (int) char_offset, (void *) sp, (void *) re_ctx.input,
 
62149
                             (void *) re_ctx.input_end);
 
62150
 
 
62151
                /*
 
62152
                 *  Note:
 
62153
                 *
 
62154
                 *    - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
 
62155
                 *      conditions; a longjmp() will terminate the entire matching process.
 
62156
                 *
 
62157
                 *    - Clearing saved[] is not necessary because backtracking does it
 
62158
                 *
 
62159
                 *    - Backtracking also rewinds ctx.recursion back to zero, unless an
 
62160
                 *      internal/limit error occurs (which causes a longjmp())
 
62161
                 *
 
62162
                 *    - If we supported anchored matches, we would break out here
 
62163
                 *      unconditionally; however, Ecmascript regexps don't have anchored
 
62164
                 *      matches.  It might make sense to implement a fast bail-out if
 
62165
                 *      the regexp begins with '^' and sp is not 0: currently we'll just
 
62166
                 *      run through the entire input string, trivially failing the match
 
62167
                 *      at every non-zero offset.
 
62168
                 */
 
62169
 
 
62170
                if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
 
62171
                        DUK_DDDPRINT("match at offset %d", (int) char_offset);
 
62172
                        match = 1;
 
62173
                        break;
 
62174
                }
 
62175
 
 
62176
                /* advance by one character (code point) and one char_offset */
 
62177
                char_offset++;
 
62178
                if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
 
62179
                        /*
 
62180
                         *  Note:
 
62181
                         *
 
62182
                         *    - Intentionally attempt (empty) match at char_offset == k_input->clen
 
62183
                         *
 
62184
                         *    - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
 
62185
                         *      -> no need or use for a negative check
 
62186
                         */
 
62187
 
 
62188
                        DUK_DDDPRINT("no match after trying all sp offsets");
 
62189
                        break;
 
62190
                }
 
62191
 
 
62192
                /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
 
62193
                (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
 
62194
        }
 
62195
 
 
62196
 match_over:
 
62197
 
 
62198
        /*
 
62199
         *  Matching complete, create result array or return a 'null'.  Update lastIndex
 
62200
         *  if necessary.  See E5 Section 15.10.6.2.
 
62201
         *
 
62202
         *  Because lastIndex is a character (not byte) offset, we need the character
 
62203
         *  length of the match which we conveniently get as a side effect of interning
 
62204
         *  the matching substring (0th index of result array).
 
62205
         *
 
62206
         *  saved[0]         start pointer (~ byte offset) of current match
 
62207
         *  saved[1]         end pointer (~ byte offset) of current match (exclusive)
 
62208
         *  char_offset      start character offset of current match (-> .index of result)
 
62209
         *  char_end_offset  end character offset (computed below)
 
62210
         */
 
62211
 
 
62212
        /* [ ... re_obj input bc saved_buf ] */
 
62213
 
 
62214
        if (match) {
 
62215
#ifdef DUK_USE_ASSERTIONS
 
62216
                duk_hobject *h_res;
 
62217
#endif
 
62218
                duk_uint32_t char_end_offset = 0;
 
62219
 
 
62220
                DUK_DDDPRINT("regexp matches at char_offset %d", (int) char_offset);
 
62221
 
 
62222
                DUK_ASSERT(re_ctx.nsaved >= 2);        /* must have start and end */
 
62223
                DUK_ASSERT((re_ctx.nsaved % 2) == 0);  /* and even number */
 
62224
 
 
62225
                /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
 
62226
                 * advantage of now.  The array is not compacted either, as regexp match
 
62227
                 * objects are usually short lived.
 
62228
                 */
 
62229
 
 
62230
                duk_push_array(ctx);
 
62231
 
 
62232
#ifdef DUK_USE_ASSERTIONS
 
62233
                h_res = duk_require_hobject(ctx, -1);
 
62234
                DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
 
62235
                DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_ARRAY(h_res));
 
62236
                DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
 
62237
#endif
 
62238
 
 
62239
                /* [ ... re_obj input bc saved_buf res_obj ] */
 
62240
 
 
62241
                duk_push_number(ctx, (double) char_offset);
 
62242
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INDEX, DUK_PROPDESC_FLAGS_WEC);
 
62243
 
 
62244
                duk_dup(ctx, -4);
 
62245
                duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INPUT, DUK_PROPDESC_FLAGS_WEC);
 
62246
 
 
62247
                for (i = 0; i < re_ctx.nsaved; i += 2) {
 
62248
                        /* Captures which are undefined have NULL pointers and are returned
 
62249
                         * as 'undefined'.  The same is done when saved[] pointers are insane
 
62250
                         * (this should, of course, never happen in practice).
 
62251
                         */
 
62252
                        if (re_ctx.saved[i] && re_ctx.saved[i+1] && re_ctx.saved[i+1] >= re_ctx.saved[i]) {
 
62253
                                duk_hstring *h_saved;
 
62254
 
 
62255
                                duk_push_lstring(ctx,
 
62256
                                                 (char *) re_ctx.saved[i],
 
62257
                                                 (size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
 
62258
                                h_saved = duk_get_hstring(ctx, -1);
 
62259
                                DUK_ASSERT(h_saved != NULL);
 
62260
 
 
62261
                                if (i == 0) {
 
62262
                                        /* Assumes that saved[0] and saved[1] are always
 
62263
                                         * set by regexp bytecode (if not, char_end_offset
 
62264
                                         * will be zero).  Also assumes clen reflects the
 
62265
                                         * correct char length.
 
62266
                                         */
 
62267
                                        char_end_offset = char_offset + DUK_HSTRING_GET_CHARLEN(h_saved);
 
62268
                                }
 
62269
                        } else {
 
62270
                                duk_push_undefined(ctx);
 
62271
                        }
 
62272
 
 
62273
                        /* [ ... re_obj input bc saved_buf res_obj val ] */
 
62274
                        duk_put_prop_index(ctx, -2, i / 2);
 
62275
                }
 
62276
 
 
62277
                /* [ ... re_obj input bc saved_buf res_obj ] */
 
62278
 
 
62279
                /* NB: 'length' property is automatically updated by the array setup loop */
 
62280
 
 
62281
                if (global) {
 
62282
                        /* global regexp: lastIndex updated on match */
 
62283
                        duk_push_number(ctx, (double) char_end_offset);
 
62284
                        duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
 
62285
                } else {
 
62286
                        /* non-global regexp: lastIndex never updated on match */
 
62287
                        ;
 
62288
                }
 
62289
        } else {
 
62290
                /*
 
62291
                 *  No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
 
62292
                 *  of 'global' flag of the RegExp.  In particular, if lastIndex is invalid
 
62293
                 *  initially, it is reset to zero.
 
62294
                 */
 
62295
 
 
62296
                DUK_DDDPRINT("regexp does not match");
 
62297
 
 
62298
                duk_push_null(ctx);
 
62299
 
 
62300
                /* [ ... re_obj input bc saved_buf res_obj ] */
 
62301
 
 
62302
                duk_push_int(ctx, 0);
 
62303
                duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
 
62304
        }
 
62305
 
 
62306
        /* [ ... re_obj input bc saved_buf res_obj ] */
 
62307
 
 
62308
        duk_insert(ctx, -5);
 
62309
 
 
62310
        /* [ ... res_obj re_obj input bc saved_buf ] */
 
62311
 
 
62312
        duk_pop_n(ctx, 4);
 
62313
 
 
62314
        /* [ ... res_obj ] */
 
62315
 
 
62316
        /* XXX: these last tricks are unnecessary if the function is made
 
62317
         * a genuine native function.
 
62318
         */
 
62319
}
 
62320
 
 
62321
void duk_regexp_match(duk_hthread *thr) {
 
62322
        duk__regexp_match_helper(thr, 0 /*force_global*/);
 
62323
}
 
62324
 
 
62325
/* This variant is needed by String.prototype.split(); it needs to perform
 
62326
 * global-style matching on a cloned RegExp which is potentially non-global.
 
62327
 */
 
62328
void duk_regexp_match_force_global(duk_hthread *thr) {
 
62329
        duk__regexp_match_helper(thr, 1 /*force_global*/);
 
62330
}
 
62331
 
 
62332
#else  /* DUK_USE_REGEXP_SUPPORT */
 
62333
 
 
62334
/* regexp support disabled */
 
62335
 
 
62336
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
62337
 
 
62338
#line 1 "duk_replacements.c"
 
62339
/*
 
62340
 *  Replacements for missing platform functions.
 
62341
 *
 
62342
 *  Unlike the originals, fpclassify() and signbit() replacements don't
 
62343
 *  work on any floating point types, only doubles.  The C typing here
 
62344
 *  mimics the standard prototypes.
 
62345
 */
 
62346
 
 
62347
#ifdef DUK_USE_COMPUTED_NAN
 
62348
double duk_computed_nan;
 
62349
#endif
 
62350
 
 
62351
#ifdef DUK_USE_COMPUTED_INFINITY
 
62352
double duk_computed_infinity;
 
62353
#endif
 
62354
 
 
62355
#ifdef DUK_USE_REPL_FPCLASSIFY
 
62356
int duk_repl_fpclassify(double x) {
 
62357
        duk_double_union u;
 
62358
        duk_uint_fast16_t exp;
 
62359
        duk_small_int_t mzero;
 
62360
 
 
62361
        u.d = x;
 
62362
        exp = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
 
62363
        if (exp > 0x0000UL && exp < 0x7ff0UL) {
 
62364
                /* exp values [0x001,0x7fe] = normal */
 
62365
                return DUK_FP_NORMAL;
 
62366
        }
 
62367
 
 
62368
        mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
 
62369
        if (exp == 0x0000UL) {
 
62370
                /* exp 0x000 is zero/subnormal */
 
62371
                if (mzero) {
 
62372
                        return DUK_FP_ZERO;
 
62373
                } else {
 
62374
                        return DUK_FP_SUBNORMAL;
 
62375
                }
 
62376
        } else {
 
62377
                /* exp 0xfff is infinite/nan */
 
62378
                if (mzero) {
 
62379
                        return DUK_FP_INFINITE;
 
62380
                } else {
 
62381
                        return DUK_FP_NAN;
 
62382
                }
 
62383
        }
 
62384
}
 
62385
#endif
 
62386
 
 
62387
#ifdef DUK_USE_REPL_SIGNBIT
 
62388
int duk_repl_signbit(double x) {
 
62389
        duk_double_union u;
 
62390
        u.d = x;
 
62391
        return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
 
62392
}
 
62393
#endif
 
62394
 
 
62395
#ifdef DUK_USE_REPL_ISFINITE
 
62396
int duk_repl_isfinite(double x) {
 
62397
        int c = DUK_FPCLASSIFY(x);
 
62398
        if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
 
62399
                return 0;
 
62400
        } else {
 
62401
                return 1;
 
62402
        }
 
62403
}
 
62404
#endif
 
62405
 
 
62406
#ifdef DUK_USE_REPL_ISNAN
 
62407
int duk_repl_isnan(double x) {
 
62408
        int c = DUK_FPCLASSIFY(x);
 
62409
        return (c == DUK_FP_NAN);
 
62410
}
 
62411
#endif
 
62412
 
 
62413
#ifdef DUK_USE_REPL_ISINF
 
62414
int duk_repl_isinf(double x) {
 
62415
        int c = DUK_FPCLASSIFY(x);
 
62416
        return (c == DUK_FP_INFINITE);
 
62417
}
 
62418
#endif
 
62419
 
 
62420
#line 1 "duk_selftest.c"
 
62421
/*
 
62422
 *  Self tests to ensure execution environment is sane.  Intended to catch
 
62423
 *  compiler/platform problems which cannot be detected at compile time.
 
62424
 */
 
62425
 
 
62426
/* include removed: duk_internal.h */
 
62427
 
 
62428
#if defined(DUK_USE_SELF_TESTS)
 
62429
 
 
62430
/*
 
62431
 *  Unions and structs for self tests
 
62432
 */
 
62433
 
 
62434
typedef union {
 
62435
        double d;
 
62436
        duk_uint8_t c[8];
 
62437
} duk__test_double_union;
 
62438
 
 
62439
#define DUK__DBLUNION_CMP_TRUE(a,b)  do { \
 
62440
                if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) != 0) { \
 
62441
                        DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
 
62442
                } \
 
62443
        } while (0)
 
62444
 
 
62445
#define DUK__DBLUNION_CMP_FALSE(a,b)  do { \
 
62446
                if (DUK_MEMCMP((void *) (a), (void *) (b), sizeof(duk__test_double_union)) == 0) { \
 
62447
                        DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
 
62448
                } \
 
62449
        } while (0)
 
62450
 
 
62451
typedef union {
 
62452
        duk_uint32_t i;
 
62453
        duk_uint8_t c[8];
 
62454
} duk__test_u32_union;
 
62455
 
 
62456
/*
 
62457
 *  Two's complement arithmetic.
 
62458
 */
 
62459
 
 
62460
static void duk__selftest_twos_complement(void) {
 
62461
        volatile int test;
 
62462
        test = -1;
 
62463
        if (((duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
 
62464
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
 
62465
        }
 
62466
}
 
62467
 
 
62468
/*
 
62469
 *  Byte order.  Important to self check, because on some exotic platforms
 
62470
 *  there is no actual detection but rather assumption based on platform
 
62471
 *  defines.
 
62472
 */
 
62473
 
 
62474
static void duk__selftest_byte_order(void) {
 
62475
        duk__test_u32_union u1;
 
62476
        duk__test_double_union u2;
 
62477
 
 
62478
        /*
 
62479
         *  >>> struct.pack('>d', 102030405060).encode('hex')
 
62480
         *  '4237c17c6dc40000'
 
62481
         */
 
62482
#if defined(DUK_USE_INTEGER_LE)
 
62483
        u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
 
62484
#elif defined(DUK_USE_INTEGER_ME)
 
62485
#error integer mixed endian not supported now
 
62486
#elif defined(DUK_USE_INTEGER_BE)
 
62487
        u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
 
62488
#else
 
62489
#error unknown integer endianness
 
62490
#endif
 
62491
 
 
62492
#if defined(DUK_USE_DOUBLE_LE)
 
62493
        u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
 
62494
        u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
 
62495
#elif defined(DUK_USE_DOUBLE_ME)
 
62496
        u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
 
62497
        u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
 
62498
#elif defined(DUK_USE_DOUBLE_BE)
 
62499
        u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
 
62500
        u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
 
62501
#else
 
62502
#error unknown double endianness
 
62503
#endif
 
62504
 
 
62505
        if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
 
62506
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
 
62507
        }
 
62508
 
 
62509
        if (u2.d != (double) 102030405060.0) {
 
62510
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
 
62511
        }
 
62512
}
 
62513
 
 
62514
/*
 
62515
 *  Basic double / byte union memory layout.
 
62516
 */
 
62517
 
 
62518
static void duk__selftest_double_union_size(void) {
 
62519
        if (sizeof(duk__test_double_union) != 8) {
 
62520
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
 
62521
        }
 
62522
}
 
62523
 
 
62524
/*
 
62525
 *  Union aliasing, see misc/clang_aliasing.c.
 
62526
 */
 
62527
 
 
62528
static void duk__selftest_double_aliasing(void) {
 
62529
        duk__test_double_union a, b;
 
62530
 
 
62531
        /* Test signaling NaN and alias assignment in all
 
62532
         * endianness combinations.
 
62533
         */
 
62534
 
 
62535
        /* little endian */
 
62536
        a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
 
62537
        a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
 
62538
        b = a;
 
62539
        DUK__DBLUNION_CMP_TRUE(&a, &b);
 
62540
 
 
62541
        /* big endian */
 
62542
        a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
 
62543
        a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
 
62544
        b = a;
 
62545
        DUK__DBLUNION_CMP_TRUE(&a, &b);
 
62546
 
 
62547
        /* mixed endian */
 
62548
        a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
 
62549
        a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
 
62550
        b = a;
 
62551
        DUK__DBLUNION_CMP_TRUE(&a, &b);
 
62552
}
 
62553
 
 
62554
/*
 
62555
 *  Zero sign, see misc/tcc_zerosign2.c.
 
62556
 */
 
62557
 
 
62558
static void duk__selftest_double_zero_sign(void) {
 
62559
        volatile duk__test_double_union a, b;
 
62560
 
 
62561
        a.d = 0.0;
 
62562
        b.d = -a.d;
 
62563
        DUK__DBLUNION_CMP_FALSE(&a, &b);
 
62564
}
 
62565
 
 
62566
/*
 
62567
 *  Struct size/alignment if platform requires it
 
62568
 *
 
62569
 *  There are some compiler specific struct padding pragmas etc in use, this
 
62570
 *  selftest ensures they're correctly detected and used.
 
62571
 */
 
62572
 
 
62573
static void duk__selftest_struct_align(void) {
 
62574
#if defined(DUK_USE_ALIGN_4)
 
62575
        if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
 
62576
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
 
62577
        }
 
62578
#elif defined(DUK_USE_ALIGN_8)
 
62579
        if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
 
62580
                DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
 
62581
        }
 
62582
#else
 
62583
        /* no check */
 
62584
#endif
 
62585
}
 
62586
 
 
62587
/*
 
62588
 *  Self test main
 
62589
 */
 
62590
 
 
62591
void duk_selftest_run_tests(void) {
 
62592
        duk__selftest_twos_complement();
 
62593
        duk__selftest_byte_order();
 
62594
        duk__selftest_double_union_size();
 
62595
        duk__selftest_double_aliasing();
 
62596
        duk__selftest_double_zero_sign();
 
62597
        duk__selftest_struct_align();
 
62598
}
 
62599
 
 
62600
#undef DUK__DBLUNION_CMP_TRUE
 
62601
#undef DUK__DBLUNION_CMP_FALSE
 
62602
 
 
62603
#endif  /* DUK_USE_SELF_TESTS */
 
62604
#line 1 "duk_unicode_support.c"
 
62605
/*
 
62606
 *  Various Unicode help functions for character classification predicates,
 
62607
 *  case conversion, decoding, etc.
 
62608
 */
 
62609
 
 
62610
/* include removed: duk_internal.h */
 
62611
 
 
62612
/*
 
62613
 *  XUTF-8 and CESU-8 encoding/decoding
 
62614
 */
 
62615
 
 
62616
duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
 
62617
        duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
 
62618
        if (x < 0x80UL) {
 
62619
                /* 7 bits */
 
62620
                return 1;
 
62621
        } else if (x < 0x800UL) {
 
62622
                /* 11 bits */
 
62623
                return 2;
 
62624
        } else if (x < 0x10000UL) {
 
62625
                /* 16 bits */
 
62626
                return 3;
 
62627
        } else if (x < 0x200000UL) {
 
62628
                /* 21 bits */
 
62629
                return 4;
 
62630
        } else if (x < 0x4000000UL) {
 
62631
                /* 26 bits */
 
62632
                return 5;
 
62633
        } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
 
62634
                /* 31 bits */
 
62635
                return 6;
 
62636
        } else {
 
62637
                /* 36 bits */
 
62638
                return 7;
 
62639
        }
 
62640
}
 
62641
 
 
62642
duk_uint8_t duk_unicode_xutf8_markers[7] = {
 
62643
        0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
 
62644
};
 
62645
 
 
62646
/* Encode to extended UTF-8; 'out' must have space for at least
 
62647
 * DUK_UNICODE_MAX_XUTF8_LENGTH bytes.  Allows encoding of any
 
62648
 * 32-bit (unsigned) codepoint.
 
62649
 */
 
62650
duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
 
62651
        duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
 
62652
        duk_small_int_t len;
 
62653
        duk_uint8_t marker;
 
62654
        duk_small_int_t i;
 
62655
 
 
62656
        len = duk_unicode_get_xutf8_length(cp);
 
62657
        DUK_ASSERT(len > 0);
 
62658
 
 
62659
        marker = duk_unicode_xutf8_markers[len - 1];  /* 64-bit OK because always >= 0 */
 
62660
 
 
62661
        i = len;
 
62662
        DUK_ASSERT(i > 0);
 
62663
        do {
 
62664
                i--;
 
62665
                if (i > 0) {
 
62666
                        out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
 
62667
                        x >>= 6;
 
62668
                } else {
 
62669
                        /* Note: masking of 'x' is not necessary because of
 
62670
                         * range check and shifting -> no bits overlapping
 
62671
                         * the marker should be set.
 
62672
                         */
 
62673
                        out[0] = (duk_uint8_t) (marker + x);
 
62674
                }
 
62675
        } while (i > 0);
 
62676
 
 
62677
        return len;
 
62678
}
 
62679
 
 
62680
/* Encode to CESU-8; 'out' must have space for at least
 
62681
 * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
 
62682
 * will encode to garbage but won't overwrite the output buffer.
 
62683
 */
 
62684
duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
 
62685
        duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
 
62686
        duk_small_int_t len;
 
62687
 
 
62688
        if (x < 0x80UL) {
 
62689
                out[0] = (duk_uint8_t) x;
 
62690
                len = 1;
 
62691
        } else if (x < 0x800UL) {
 
62692
                out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
 
62693
                out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
 
62694
                len = 2;
 
62695
        } else if (x < 0x10000UL) {
 
62696
                /* surrogate pairs get encoded here */
 
62697
                out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
 
62698
                out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
 
62699
                out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
 
62700
                len = 3;
 
62701
        } else {
 
62702
                /*
 
62703
                 *  Unicode codepoints above U+FFFF are encoded as surrogate
 
62704
                 *  pairs here.  This ensures that all CESU-8 codepoints are
 
62705
                 *  16-bit values as expected in Ecmascript.  The surrogate
 
62706
                 *  pairs always get a 3-byte encoding (each) in CESU-8.
 
62707
                 *  See: http://en.wikipedia.org/wiki/Surrogate_pair
 
62708
                 *
 
62709
                 *  20-bit codepoint, 10 bits (A and B) per surrogate pair:
 
62710
                 * 
 
62711
                 *    x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
 
62712
                 *  sp1 = 0b110110AA AAAAAAAA  (0xd800 + ((x >> 10) & 0x3ff))
 
62713
                 *  sp2 = 0b110111BB BBBBBBBB  (0xdc00 + (x & 0x3ff))
 
62714
                 *
 
62715
                 *  Encoded into CESU-8:
 
62716
                 *
 
62717
                 *  sp1 -> 0b11101101  (0xe0 + ((sp1 >> 12) & 0x0f))
 
62718
                 *      -> 0b1010AAAA  (0x80 + ((sp1 >> 6) & 0x3f))
 
62719
                 *      -> 0b10AAAAAA  (0x80 + (sp1 & 0x3f))
 
62720
                 *  sp2 -> 0b11101101  (0xe0 + ((sp2 >> 12) & 0x0f))
 
62721
                 *      -> 0b1011BBBB  (0x80 + ((sp2 >> 6) & 0x3f))
 
62722
                 *      -> 0b10BBBBBB  (0x80 + (sp2 & 0x3f))
 
62723
                 *
 
62724
                 *  Note that 0x10000 must be subtracted first.  The code below
 
62725
                 *  avoids the sp1, sp2 temporaries which saves around 20 bytes
 
62726
                 *  of code.
 
62727
                 */
 
62728
 
 
62729
                x -= 0x10000UL;
 
62730
 
 
62731
                out[0] = (duk_uint8_t) (0xed);
 
62732
                out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
 
62733
                out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
 
62734
                out[3] = (duk_uint8_t) (0xed);
 
62735
                out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
 
62736
                out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
 
62737
                len = 6;
 
62738
        }
 
62739
 
 
62740
        return len;
 
62741
}
 
62742
 
 
62743
/* Decode helper.  Return zero on error. */
 
62744
duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) {
 
62745
        duk_uint8_t *p;
 
62746
        duk_uint32_t res;
 
62747
        duk_uint_fast8_t ch;
 
62748
        duk_small_int_t n;
 
62749
 
 
62750
        DUK_UNREF(thr);
 
62751
 
 
62752
        p = *ptr;
 
62753
        if (p < ptr_start || p >= ptr_end) {
 
62754
                goto fail;
 
62755
        }
 
62756
 
 
62757
        /*
 
62758
         *  UTF-8 decoder which accepts longer than standard byte sequences.
 
62759
         *  This allows full 32-bit code points to be used.
 
62760
         */
 
62761
 
 
62762
        ch = (duk_uint_fast8_t) (*p++);
 
62763
        if (ch < 0x80) {
 
62764
                /* 0xxx xxxx   [7 bits] */
 
62765
                res = (duk_uint32_t) (ch & 0x7f);
 
62766
                n = 0;
 
62767
        } else if (ch < 0xc0) {
 
62768
                /* 10xx xxxx -> invalid */
 
62769
                goto fail;
 
62770
        } else if (ch < 0xe0) {
 
62771
                /* 110x xxxx   10xx xxxx   [11 bits] */
 
62772
                res = (duk_uint32_t) (ch & 0x1f);
 
62773
                n = 1;
 
62774
        } else if (ch < 0xf0) {
 
62775
                /* 1110 xxxx   10xx xxxx   10xx xxxx   [16 bits] */
 
62776
                res = (duk_uint32_t) (ch & 0x0f);
 
62777
                n = 2;
 
62778
        } else if (ch < 0xf8) {
 
62779
                /* 1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx   [21 bits] */
 
62780
                res = (duk_uint32_t) (ch & 0x07);
 
62781
                n = 3;
 
62782
        } else if (ch < 0xfc) {
 
62783
                /* 1111 10xx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [26 bits] */
 
62784
                res = (duk_uint32_t) (ch & 0x03);
 
62785
                n = 4;
 
62786
        } else if (ch < 0xfe) {
 
62787
                /* 1111 110x   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [31 bits] */
 
62788
                res = (duk_uint32_t) (ch & 0x01);
 
62789
                n = 5;
 
62790
        } else if (ch < 0xff) {
 
62791
                /* 1111 1110   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [36 bits] */
 
62792
                res = (duk_uint32_t) (0);
 
62793
                n = 6;
 
62794
        } else {
 
62795
                /* 8-byte format could be:
 
62796
                 * 1111 1111   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [41 bits]
 
62797
                 *
 
62798
                 * However, this format would not have a zero bit following the
 
62799
                 * leading one bits and would not allow 0xFF to be used as an
 
62800
                 * "invalid xutf-8" marker for internal keys.  Further, 8-byte
 
62801
                 * encodings (up to 41 bit code points) are not currently needed.
 
62802
                 */
 
62803
                goto fail;
 
62804
        }
 
62805
 
 
62806
        DUK_ASSERT(p >= ptr_start);  /* verified at beginning */
 
62807
        if (p + n > ptr_end) {
 
62808
                /* check pointer at end */
 
62809
                goto fail;
 
62810
        }
 
62811
 
 
62812
        while (n > 0) {
 
62813
                DUK_ASSERT(p >= ptr_start && p < ptr_end);
 
62814
                res = res << 6;
 
62815
                res += (duk_uint32_t) ((*p++) & 0x3f);
 
62816
                n--;
 
62817
        }
 
62818
 
 
62819
        *ptr = p;
 
62820
        *out_cp = res;
 
62821
        return 1;
 
62822
 
 
62823
 fail:
 
62824
        return 0;
 
62825
}
 
62826
 
 
62827
/* used by e.g. duk_regexp_executor.c, string built-ins */
 
62828
duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, duk_uint8_t **ptr, duk_uint8_t *ptr_start, duk_uint8_t *ptr_end) {
 
62829
        duk_ucodepoint_t cp;
 
62830
 
 
62831
        if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
 
62832
                return cp;
 
62833
        }
 
62834
        DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "utf-8 decode failed");
 
62835
        DUK_UNREACHABLE();
 
62836
        return 0;
 
62837
}
 
62838
 
 
62839
/* (extended) utf-8 length without codepoint encoding validation, used
 
62840
 * for string interning (should probably be inlined).
 
62841
 */
 
62842
duk_size_t duk_unicode_unvalidated_utf8_length(duk_uint8_t *data, duk_size_t blen) {
 
62843
        duk_uint8_t *p = data;
 
62844
        duk_uint8_t *p_end = data + blen;
 
62845
        duk_size_t clen = 0;
 
62846
 
 
62847
        while (p < p_end) {
 
62848
                duk_uint8_t x = *p++;
 
62849
                if (x < 0x80 || x >= 0xc0) {
 
62850
                        /* 10xxxxxx = continuation chars (0x80...0xbf), above
 
62851
                         * and below that initial bytes.
 
62852
                         */
 
62853
                        clen++;
 
62854
                }
 
62855
        }
 
62856
 
 
62857
        return clen;
 
62858
}
 
62859
 
 
62860
/*
 
62861
 *  Unicode range matcher
 
62862
 *
 
62863
 *  Matches a codepoint against a packed bitstream of character ranges.
 
62864
 *  Used for slow path Unicode matching.
 
62865
 */
 
62866
 
 
62867
/* Must match src/extract_chars.py, generate_match_table3(). */
 
62868
static duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
 
62869
        duk_uint32_t t;
 
62870
 
 
62871
        t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
 
62872
        if (t <= 0x0eU) {
 
62873
                return t;
 
62874
        }
 
62875
        t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
 
62876
        if (t <= 0xfdU) {
 
62877
                return t + 0x0f;
 
62878
        }
 
62879
        if (t == 0xfeU) {
 
62880
                t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
 
62881
                return t + 0x0fU + 0xfeU;
 
62882
        } else {
 
62883
                t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
 
62884
                return t + 0x0fU + 0xfeU + 0x1000UL;
 
62885
        }
 
62886
}
 
62887
 
 
62888
static duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
 
62889
        duk_bitdecoder_ctx bd_ctx;
 
62890
        duk_codepoint_t prev_re;
 
62891
 
 
62892
        DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
 
62893
        bd_ctx.data = (duk_uint8_t *) unitab;
 
62894
        bd_ctx.length = (duk_size_t) unilen;
 
62895
 
 
62896
        prev_re = 0;
 
62897
        for (;;) {
 
62898
                duk_codepoint_t r1, r2;
 
62899
                r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
 
62900
                if (r1 == 0) {
 
62901
                        break;
 
62902
                }
 
62903
                r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
 
62904
 
 
62905
                r1 = prev_re + r1;
 
62906
                r2 = r1 + r2;
 
62907
                prev_re = r2;
 
62908
 
 
62909
                /* [r1,r2] is the range */
 
62910
 
 
62911
                DUK_DDDPRINT("duk__uni_range_match: cp=%06x range=[0x%06x,0x%06x]", (int) cp, (int) r1, (int) r2);
 
62912
                if (cp >= r1 && cp <= r2) {
 
62913
                        return 1;
 
62914
                }
 
62915
        }
 
62916
 
 
62917
        return 0;
 
62918
}
 
62919
 
 
62920
/*
 
62921
 *  "WhiteSpace" production check.
 
62922
 */
 
62923
 
 
62924
duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
 
62925
        /*
 
62926
         *  E5 Section 7.2 specifies six characters specifically as
 
62927
         *  white space:
 
62928
         *
 
62929
         *    0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
 
62930
         *    000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
 
62931
         *    000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
 
62932
         *    0020;SPACE;Zs;0;WS;;;;;N;;;;;
 
62933
         *    00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
 
62934
         *    FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
 
62935
         *
 
62936
         *  It also specifies any Unicode category 'Zs' characters as white
 
62937
         *  space.  These can be extracted with the "src/extract_chars.py" script.
 
62938
         *  Current result:
 
62939
         *  
 
62940
         *    RAW OUTPUT:
 
62941
         *    ===========
 
62942
         *    0020;SPACE;Zs;0;WS;;;;;N;;;;;
 
62943
         *    00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
 
62944
         *    1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
 
62945
         *    180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
 
62946
         *    2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
 
62947
         *    2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
 
62948
         *    2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62949
         *    2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62950
         *    2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62951
         *    2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62952
         *    2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62953
         *    2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
 
62954
         *    2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62955
         *    2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62956
         *    200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62957
         *    202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
 
62958
         *    205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
 
62959
         *    3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
 
62960
         *  
 
62961
         *    RANGES:
 
62962
         *    =======
 
62963
         *    0x0020
 
62964
         *    0x00a0
 
62965
         *    0x1680
 
62966
         *    0x180e
 
62967
         *    0x2000 ... 0x200a
 
62968
         *    0x202f
 
62969
         *    0x205f
 
62970
         *    0x3000
 
62971
         *
 
62972
         *  A manual decoder (below) is probably most compact for this.
 
62973
         */
 
62974
 
 
62975
        duk_uint_fast8_t lo;
 
62976
        duk_uint_fast32_t hi;
 
62977
 
 
62978
        /* cp == -1 (EOF) never matches and causes return value 0 */
 
62979
 
 
62980
        lo = (duk_uint_fast8_t) (cp & 0xff);
 
62981
        hi = (duk_uint_fast32_t) (cp >> 8);  /* does not fit into an uchar */
 
62982
 
 
62983
        if (hi == 0x0000UL) {
 
62984
                if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
 
62985
                    lo == 0x20U || lo == 0xa0U) {
 
62986
                        return 1;
 
62987
                }
 
62988
        } else if (hi == 0x0020UL) {
 
62989
                if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
 
62990
                        return 1;
 
62991
                }
 
62992
        } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
 
62993
                   cp == 0xfeffL) {
 
62994
                return 1;
 
62995
        }
 
62996
 
 
62997
        return 0;
 
62998
}
 
62999
 
 
63000
/*
 
63001
 *  "LineTerminator" production check.
 
63002
 */
 
63003
 
 
63004
duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
 
63005
        /*
 
63006
         *  E5 Section 7.3
 
63007
         *
 
63008
         *  A LineTerminatorSequence essentially merges <CR> <LF> sequences
 
63009
         *  into a single line terminator.  This must be handled by the caller.
 
63010
         */
 
63011
 
 
63012
        if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
 
63013
            cp == 0x2029L) {
 
63014
                return 1;
 
63015
        }
 
63016
 
 
63017
        return 0;
 
63018
}
 
63019
 
 
63020
/*
 
63021
 *  "IdentifierStart" production check.
 
63022
 */
 
63023
 
 
63024
duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
 
63025
        /*
 
63026
         *  E5 Section 7.6:
 
63027
         *
 
63028
         *    IdentifierStart:
 
63029
         *      UnicodeLetter
 
63030
         *      $
 
63031
         *      _
 
63032
         *      \ UnicodeEscapeSequence
 
63033
         *
 
63034
         *  IdentifierStart production has one multi-character production:
 
63035
         *
 
63036
         *    \ UnicodeEscapeSequence
 
63037
         *
 
63038
         *  The '\' character is -not- matched by this function.  Rather, the caller
 
63039
         *  should decode the escape and then call this function to check whether the
 
63040
         *  decoded character is acceptable (see discussion in E5 Section 7.6).
 
63041
         *
 
63042
         *  The "UnicodeLetter" alternative of the production allows letters
 
63043
         *  from various Unicode categories.  These can be extracted with the
 
63044
         *  "src/extract_chars.py" script.
 
63045
         *
 
63046
         *  Because the result has hundreds of Unicode codepoint ranges, matching
 
63047
         *  for any values >= 0x80 are done using a very slow range-by-range scan
 
63048
         *  and a packed range format.
 
63049
         *
 
63050
         *  The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
 
63051
         *  it matters the most.  The ASCII related ranges of IdentifierStart are:
 
63052
         *
 
63053
         *    0x0041 ... 0x005a         ['A' ... 'Z']
 
63054
         *    0x0061 ... 0x007a         ['a' ... 'z']
 
63055
         *    0x0024                    ['$']
 
63056
         *    0x005f                    ['_']
 
63057
         */
 
63058
 
 
63059
        /* ASCII (and EOF) fast path -- quick accept and reject */
 
63060
        if (cp <= 0x7fL) {
 
63061
                if ((cp >= 'a' && cp <= 'z') ||
 
63062
                    (cp >= 'A' && cp <= 'Z') ||
 
63063
                    cp == '_' || cp == '$') {
 
63064
                        return 1;
 
63065
                }
 
63066
                return 0;
 
63067
        }
 
63068
 
 
63069
        /* Non-ASCII slow path (range-by-range linear comparison), very slow */
 
63070
 
 
63071
#ifdef DUK_USE_SOURCE_NONBMP
 
63072
        if (duk__uni_range_match(duk_unicode_ids_noa,
 
63073
                                 (duk_size_t) sizeof(duk_unicode_ids_noa),
 
63074
                                 (duk_codepoint_t) cp)) {
 
63075
                return 1;
 
63076
        }
 
63077
        return 0;
 
63078
#else
 
63079
        if (cp < 0x10000L) {
 
63080
                if (duk__uni_range_match(duk_unicode_ids_noabmp,
 
63081
                                         sizeof(duk_unicode_ids_noabmp),
 
63082
                                         (duk_codepoint_t) cp)) {
 
63083
                        return 1;
 
63084
                }
 
63085
                return 0;
 
63086
        } else {
 
63087
                /* without explicit non-BMP support, assume non-BMP characters
 
63088
                 * are always accepted as identifier characters.
 
63089
                 */
 
63090
                return 1;
 
63091
        }
 
63092
#endif
 
63093
}
 
63094
 
 
63095
/*
 
63096
 *  "IdentifierPart" production check.
 
63097
 */
 
63098
 
 
63099
duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
 
63100
        /*
 
63101
         *  E5 Section 7.6:
 
63102
         *
 
63103
         *    IdentifierPart:
 
63104
         *      IdentifierStart
 
63105
         *      UnicodeCombiningMark
 
63106
         *      UnicodeDigit
 
63107
         *      UnicodeConnectorPunctuation
 
63108
         *      <ZWNJ>  [U+200C]
 
63109
         *      <ZWJ>   [U+200D]
 
63110
         *
 
63111
         *  IdentifierPart production has one multi-character production
 
63112
         *  as part of its IdentifierStart alternative.  The '\' character
 
63113
         *  of an escape sequence is not matched here, see discussion in
 
63114
         *  duk_unicode_is_identifier_start().
 
63115
         *
 
63116
         *  To match non-ASCII characters (codepoints >= 0x80), a very slow
 
63117
         *  linear range-by-range scan is used.  The codepoint is first compared
 
63118
         *  to the IdentifierStart ranges, and if it doesn't match, then to a
 
63119
         *  set consisting of code points in IdentifierPart but not in
 
63120
         *  IdentifierStart.  This is done to keep the unicode range data small,
 
63121
         *  at the expense of speed.
 
63122
         *
 
63123
         *  The ASCII fast path consists of:
 
63124
         *
 
63125
         *    0x0030 ... 0x0039         ['0' ... '9', UnicodeDigit]
 
63126
         *    0x0041 ... 0x005a         ['A' ... 'Z', IdentifierStart]
 
63127
         *    0x0061 ... 0x007a         ['a' ... 'z', IdentifierStart]
 
63128
         *    0x0024                    ['$', IdentifierStart]
 
63129
         *    0x005f                    ['_', IdentifierStart and
 
63130
         *                               UnicodeConnectorPunctuation]
 
63131
         *
 
63132
         *  UnicodeCombiningMark has no code points <= 0x7f.
 
63133
         *
 
63134
         *  The matching code reuses the "identifier start" tables, and then
 
63135
         *  consults a separate range set for characters in "identifier part"
 
63136
         *  but not in "identifier start".  These can be extracted with the
 
63137
         *  "src/extract_chars.py" script.
 
63138
         *
 
63139
         *  UnicodeCombiningMark -> categories Mn, Mc
 
63140
         *  UnicodeDigit -> categories Nd
 
63141
         *  UnicodeConnectorPunctuation -> categories Pc
 
63142
         */
 
63143
 
 
63144
        /* ASCII (and EOF) fast path -- quick accept and reject */
 
63145
        if (cp <= 0x7fL) {
 
63146
                if ((cp >= 'a' && cp <= 'z') ||
 
63147
                    (cp >= 'A' && cp <= 'Z') ||
 
63148
                    (cp >= '0' && cp <= '9') ||
 
63149
                    cp == '_' || cp == '$') {
 
63150
                        return 1;
 
63151
                }
 
63152
                return 0;
 
63153
        }
 
63154
 
 
63155
        /* Non-ASCII slow path (range-by-range linear comparison), very slow */
 
63156
 
 
63157
#ifdef DUK_USE_SOURCE_NONBMP
 
63158
        if (duk__uni_range_match(duk_unicode_ids_noa,
 
63159
                                 sizeof(duk_unicode_ids_noa),
 
63160
                                 (duk_codepoint_t) cp) ||
 
63161
            duk__uni_range_match(duk_unicode_idp_m_ids_noa,
 
63162
                                 sizeof(duk_unicode_idp_m_ids_noa),
 
63163
                                 (duk_codepoint_t) cp)) {
 
63164
                return 1;
 
63165
        }
 
63166
        return 0;
 
63167
#else
 
63168
        if (cp < 0x10000L) {
 
63169
                if (duk__uni_range_match(duk_unicode_ids_noabmp,
 
63170
                                         sizeof(duk_unicode_ids_noabmp),
 
63171
                                         (duk_codepoint_t) cp) ||
 
63172
                    duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
 
63173
                                         sizeof(duk_unicode_idp_m_ids_noabmp),
 
63174
                                         (duk_codepoint_t) cp)) {
 
63175
                        return 1;
 
63176
                }
 
63177
                return 0;
 
63178
        } else {
 
63179
                /* without explicit non-BMP support, assume non-BMP characters
 
63180
                 * are always accepted as identifier characters.
 
63181
                 */
 
63182
                return 1;
 
63183
        }
 
63184
#endif
 
63185
}
 
63186
 
 
63187
/*
 
63188
 *  Unicode letter check.
 
63189
 */
 
63190
 
 
63191
duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
 
63192
        /*
 
63193
         *  Unicode letter is now taken to be the categories:
 
63194
         *
 
63195
         *    Lu, Ll, Lt, Lm, Lo
 
63196
         *
 
63197
         *  (Not sure if this is exactly correct.)
 
63198
         *
 
63199
         *  The ASCII fast path consists of:
 
63200
         *
 
63201
         *    0x0041 ... 0x005a         ['A' ... 'Z']
 
63202
         *    0x0061 ... 0x007a         ['a' ... 'z']
 
63203
         */
 
63204
 
 
63205
        /* ASCII (and EOF) fast path -- quick accept and reject */
 
63206
        if (cp <= 0x7fL) {
 
63207
                if ((cp >= 'a' && cp <= 'z') ||
 
63208
                    (cp >= 'A' && cp <= 'Z')) {
 
63209
                        return 1;
 
63210
                }
 
63211
                return 0;
 
63212
        }
 
63213
 
 
63214
        /* Non-ASCII slow path (range-by-range linear comparison), very slow */
 
63215
 
 
63216
#ifdef DUK_USE_SOURCE_NONBMP
 
63217
        if (duk__uni_range_match(duk_unicode_ids_noa,
 
63218
                                 sizeof(duk_unicode_ids_noa),
 
63219
                                 (duk_codepoint_t) cp) &&
 
63220
            !duk__uni_range_match(duk_unicode_ids_m_let_noa,
 
63221
                                  sizeof(duk_unicode_ids_m_let_noa),
 
63222
                                  (duk_codepoint_t) cp)) {
 
63223
                return 1;
 
63224
        }
 
63225
        return 0;
 
63226
#else
 
63227
        if (cp < 0x10000L) {
 
63228
                if (duk__uni_range_match(duk_unicode_ids_noabmp,
 
63229
                                         sizeof(duk_unicode_ids_noabmp),
 
63230
                                         (duk_codepoint_t) cp) &&
 
63231
                    !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
 
63232
                                          sizeof(duk_unicode_ids_m_let_noabmp),
 
63233
                                          (duk_codepoint_t) cp)) {
 
63234
                        return 1;
 
63235
                }
 
63236
                return 0;
 
63237
        } else {
 
63238
                /* without explicit non-BMP support, assume non-BMP characters
 
63239
                 * are always accepted as letters.
 
63240
                 */
 
63241
                return 1;
 
63242
        }
 
63243
#endif
 
63244
}
 
63245
 
 
63246
/*
 
63247
 *  Complex case conversion helper which decodes a bit-packed conversion
 
63248
 *  control stream generated by unicode/extract_caseconv.py.  The conversion
 
63249
 *  is very slow because it runs through the conversion data in a linear
 
63250
 *  fashion to save space (which is why ASCII characters have a special
 
63251
 *  fast path before arriving here).
 
63252
 * 
 
63253
 *  The particular bit counts etc have been determined experimentally to
 
63254
 *  be small but still sufficient, and must match the Python script
 
63255
 *  (src/extract_caseconv.py).
 
63256
 *
 
63257
 *  The return value is the case converted codepoint or -1 if the conversion
 
63258
 *  results in multiple characters (this is useful for regexp Canonicalization
 
63259
 *  operation).  If 'buf' is not NULL, the result codepoint(s) are also
 
63260
 *  appended to the hbuffer.
 
63261
 *
 
63262
 *  Context and locale specific rules must be checked before consulting
 
63263
 *  this function.
 
63264
 */
 
63265
 
 
63266
static duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
 
63267
                                                 duk_hbuffer_dynamic *buf,
 
63268
                                                 duk_codepoint_t cp,
 
63269
                                                 duk_bitdecoder_ctx *bd_ctx) {
 
63270
        duk_small_int_t skip = 0;
 
63271
        duk_small_int_t n;
 
63272
        duk_small_int_t t;
 
63273
        duk_small_int_t count;
 
63274
        duk_codepoint_t tmp_cp;
 
63275
        duk_codepoint_t start_i;
 
63276
        duk_codepoint_t start_o;
 
63277
 
 
63278
        DUK_DDDPRINT("slow case conversion for codepoint: %d", (int) cp);
 
63279
 
 
63280
        /* range conversion with a "skip" */
 
63281
        DUK_DDDPRINT("checking ranges");
 
63282
        for (;;) {
 
63283
                skip++;
 
63284
                n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
 
63285
                if (n == 0x3f) {
 
63286
                        /* end marker */
 
63287
                        break;
 
63288
                }
 
63289
                DUK_DDDPRINT("skip=%d, n=%d", (int) skip, (int) n);
 
63290
 
 
63291
                while (n--) {
 
63292
                        start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63293
                        start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63294
                        count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
 
63295
                        DUK_DDDPRINT("range: start_i=%d, start_o=%d, count=%d, skip=%d",
 
63296
                                     (int) start_i, (int) start_o, (int) count, (int) skip);
 
63297
 
 
63298
                        if (cp >= start_i) {
 
63299
                                tmp_cp = cp - start_i;  /* always >= 0 */
 
63300
                                if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
 
63301
                                    (tmp_cp % (duk_codepoint_t) skip) == 0) {
 
63302
                                        DUK_DDDPRINT("range matches input codepoint");
 
63303
                                        cp = start_o + tmp_cp;
 
63304
                                        goto single;
 
63305
                                }
 
63306
                        }
 
63307
                }
 
63308
        }
 
63309
 
 
63310
        /* 1:1 conversion */
 
63311
        n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
 
63312
        DUK_DDDPRINT("checking 1:1 conversions (count %d)", (int) n);
 
63313
        while (n--) {
 
63314
                start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63315
                start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63316
                DUK_DDDPRINT("1:1 conversion %d -> %d", (int) start_i, (int) start_o);
 
63317
                if (cp == start_i) {
 
63318
                        DUK_DDDPRINT("1:1 matches input codepoint");
 
63319
                        cp = start_o;
 
63320
                        goto single;
 
63321
                }
 
63322
        }
 
63323
 
 
63324
        /* complex, multicharacter conversion */
 
63325
        n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
 
63326
        DUK_DDDPRINT("checking 1:n conversions (count %d)", n);
 
63327
        while (n--) {
 
63328
                start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63329
                t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
 
63330
                DUK_DDDPRINT("1:n conversion %d -> %d chars", (int) start_i, (int) t);
 
63331
                if (cp == start_i) {
 
63332
                        DUK_DDDPRINT("1:n matches input codepoint");
 
63333
                        if (buf) {
 
63334
                                while (t--) {
 
63335
                                        tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
 
63336
                                        DUK_ASSERT(buf != NULL);
 
63337
                                        duk_hbuffer_append_xutf8(thr, buf, (duk_uint32_t) tmp_cp);  /* FIXME: duk_codepoint_t */
 
63338
                                }
 
63339
                        }
 
63340
                        return -1;
 
63341
                } else {
 
63342
                        while (t--) {
 
63343
                                (void) duk_bd_decode(bd_ctx, 16);
 
63344
                        }
 
63345
                }
 
63346
        }
 
63347
 
 
63348
        /* default: no change */
 
63349
        DUK_DDDPRINT("no rule matches, output is same as input");
 
63350
        /* fall through */
 
63351
 
 
63352
 single:
 
63353
        if (buf) {
 
63354
                duk_hbuffer_append_xutf8(thr, buf, cp);
 
63355
        }
 
63356
        return cp;
 
63357
}
 
63358
 
 
63359
/*
 
63360
 *  Case conversion helper, with context/local sensitivity.
 
63361
 *  For proper case conversion, one needs to know the character
 
63362
 *  and the preceding and following characters, as well as
 
63363
 *  locale/language.
 
63364
 */
 
63365
 
 
63366
/* XXX: add 'language' argument when locale/language sensitive rule
 
63367
 * support added.
 
63368
 */
 
63369
static duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
 
63370
                                                  duk_hbuffer_dynamic *buf,
 
63371
                                                  duk_codepoint_t cp,
 
63372
                                                  duk_codepoint_t prev,
 
63373
                                                  duk_codepoint_t next,
 
63374
                                                  duk_small_int_t uppercase) {
 
63375
        duk_bitdecoder_ctx bd_ctx;
 
63376
 
 
63377
        /* fast path for ASCII */
 
63378
        if (cp < 0x80L) {
 
63379
                /* XXX: there are language sensitive rules for the ASCII range.
 
63380
                 * If/when language/locale support is implemented, they need to
 
63381
                 * be implemented here for the fast path.  There are no context
 
63382
                 * sensitive rules for ASCII range.
 
63383
                 */
 
63384
 
 
63385
                if (uppercase) {
 
63386
                        if (cp >= 'a' && cp <= 'z') {
 
63387
                                cp = cp - 'a' + 'A';
 
63388
                        }
 
63389
                } else {
 
63390
                        if (cp >= 'A' && cp <= 'Z') {
 
63391
                                cp = cp - 'A' + 'a';
 
63392
                        }
 
63393
                }
 
63394
                goto singlechar;
 
63395
        }
 
63396
 
 
63397
        /* context and locale specific rules which cannot currently be represented
 
63398
         * in the caseconv bitstream: hardcoded rules in C
 
63399
         */
 
63400
        if (uppercase) {
 
63401
                /* XXX: turkish / azeri not implemented */
 
63402
        } else {
 
63403
                /*
 
63404
                 *  Final sigma context specific rule.  This is a rather tricky rule
 
63405
                 *  and this handling is probably not 100% correct now.
 
63406
                 */
 
63407
 
 
63408
                if (cp == 0x03a3L &&    /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
 
63409
                    duk_unicode_is_letter(prev) &&        /* prev exists and is not a letter */
 
63410
                    !duk_unicode_is_letter(next)) {       /* next does not exist or next is not a letter */
 
63411
                        /* Capital sigma occurred at "end of word", lowercase to
 
63412
                         * U+03C2 = GREEK SMALL LETTER FINAL SIGMA.  Otherwise
 
63413
                         * fall through and let the normal rules lowercase it to
 
63414
                         * U+03C3 = GREEK SMALL LETTER SIGMA.
 
63415
                         */
 
63416
                        cp = 0x03c2L;
 
63417
                        goto singlechar;
 
63418
                }
 
63419
 
 
63420
                /* XXX: lithuanian not implemented */
 
63421
                /* XXX: lithuanian, explicit dot rules */
 
63422
                /* XXX: turkish / azeri, lowercase rules */
 
63423
#if 0
 
63424
                if (0 /* language == 'lt' */ &&
 
63425
                    cp == 0x0307L) {               /* U+0307 = COMBINING DOT ABOVE */
 
63426
                        goto nochar;
 
63427
                }
 
63428
#endif
 
63429
        }
 
63430
 
 
63431
        /* 1:1 or special conversions, but not locale/context specific: script generated rules */
 
63432
        DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
 
63433
        if (uppercase) {
 
63434
                bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_uc;
 
63435
                bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
 
63436
        } else {
 
63437
                bd_ctx.data = (duk_uint8_t *) duk_unicode_caseconv_lc;
 
63438
                bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
 
63439
        }
 
63440
        return duk__slow_case_conversion(thr, buf, cp, &bd_ctx);
 
63441
 
 
63442
 singlechar:
 
63443
        if (buf) {
 
63444
                duk_hbuffer_append_xutf8(thr, buf, cp);
 
63445
        }
 
63446
        return cp;
 
63447
 
 
63448
 /* unused now, not needed until Turkish/Azeri */
 
63449
#if 0
 
63450
 nochar:
 
63451
        return -1;
 
63452
#endif
 
63453
}
 
63454
 
 
63455
/*
 
63456
 *  Replace valstack top with case converted version.
 
63457
 */
 
63458
 
 
63459
void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
 
63460
        duk_context *ctx = (duk_context *) thr;
 
63461
        duk_hstring *h_input;
 
63462
        duk_hbuffer_dynamic *h_buf;
 
63463
        duk_uint8_t *p, *p_start, *p_end;
 
63464
        duk_codepoint_t prev, curr, next;
 
63465
 
 
63466
        h_input = duk_require_hstring(ctx, -1);
 
63467
        DUK_ASSERT(h_input != NULL);
 
63468
 
 
63469
        /* XXX: should init the buffer with a spare of at least h_input->blen
 
63470
         * to avoid unnecessary growth steps.
 
63471
         */
 
63472
        duk_push_dynamic_buffer(ctx, 0);
 
63473
        h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
 
63474
        DUK_ASSERT(h_buf != NULL);
 
63475
        DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf));
 
63476
 
 
63477
        /* [ ... input buffer ] */
 
63478
 
 
63479
        p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
 
63480
        p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
 
63481
        p = p_start;
 
63482
 
 
63483
        prev = -1; DUK_UNREF(prev);
 
63484
        curr = -1;
 
63485
        next = -1;
 
63486
        for (;;) {
 
63487
                prev = curr;
 
63488
                curr = next;
 
63489
                next = -1;
 
63490
                if (p < p_end) {
 
63491
                        next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
 
63492
                } else {
 
63493
                        /* end of input and last char has been processed */
 
63494
                        if (curr < 0) {
 
63495
                                break;
 
63496
                        }
 
63497
                }
 
63498
 
 
63499
                /* on first round, skip */
 
63500
                if (curr >= 0) {
 
63501
                        /* may generate any number of output codepoints */
 
63502
                        duk__case_transform_helper(thr,
 
63503
                                                   h_buf,
 
63504
                                                   (duk_codepoint_t) curr,
 
63505
                                                   prev,
 
63506
                                                   next,
 
63507
                                                   uppercase);
 
63508
                }
 
63509
        }
 
63510
 
 
63511
        duk_to_string(ctx, -1);  /* invalidates h_buf pointer */
 
63512
        duk_remove(ctx, -2);
 
63513
}
 
63514
 
 
63515
#ifdef DUK_USE_REGEXP_SUPPORT
 
63516
 
 
63517
/*
 
63518
 *  Canonicalize() abstract operation needed for canonicalization of individual
 
63519
 *  codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
 
63520
 *  Note that codepoints are canonicalized one character at a time, so no context
 
63521
 *  specific rules can apply.  Locale specific rules can apply, though.
 
63522
 */
 
63523
 
 
63524
duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
 
63525
        duk_codepoint_t y;
 
63526
 
 
63527
        y = duk__case_transform_helper(thr,
 
63528
                                       NULL,    /* buf */
 
63529
                                       cp,      /* curr char */
 
63530
                                       -1,      /* prev char */
 
63531
                                       -1,      /* next char */
 
63532
                                       1);      /* uppercase */
 
63533
 
 
63534
        if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
 
63535
                /* multiple codepoint conversion or non-ASCII mapped to ASCII
 
63536
                 * --> leave as is.
 
63537
                 */
 
63538
                return cp;
 
63539
        }
 
63540
 
 
63541
        return y;
 
63542
}
 
63543
 
 
63544
/*
 
63545
 *  E5 Section 15.10.2.6 "IsWordChar" abstract operation.  Assume
 
63546
 *  x < 0 for characters read outside the string.
 
63547
 */
 
63548
 
 
63549
duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
 
63550
        /*
 
63551
         *  Note: the description in E5 Section 15.10.2.6 has a typo, it
 
63552
         *  contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
 
63553
         */
 
63554
        if ((x >= '0' && x <= '9') ||
 
63555
            (x >= 'a' && x <= 'z') ||
 
63556
            (x >= 'A' && x <= 'Z') ||
 
63557
            (x == '_')) {
 
63558
                return 1;
 
63559
        }
 
63560
        return 0;
 
63561
}
 
63562
 
 
63563
/*
 
63564
 *  Regexp range tables
 
63565
 */
 
63566
 
 
63567
/* exposed because lexer needs these too */
 
63568
duk_uint16_t duk_unicode_re_ranges_digit[2] = {
 
63569
        (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
 
63570
};
 
63571
duk_uint16_t duk_unicode_re_ranges_white[22] = {
 
63572
        (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
 
63573
        (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
 
63574
        (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
 
63575
        (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
 
63576
        (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
 
63577
        (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
 
63578
        (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
 
63579
        (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
 
63580
        (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
 
63581
        (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
 
63582
        (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
 
63583
};
 
63584
duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
 
63585
        (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
 
63586
        (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
 
63587
        (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
 
63588
        (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
 
63589
};
 
63590
duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
 
63591
        (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
 
63592
        (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
 
63593
};
 
63594
duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
 
63595
        (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
 
63596
        (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
 
63597
        (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
 
63598
        (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
 
63599
        (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
 
63600
        (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
 
63601
        (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
 
63602
        (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
 
63603
        (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
 
63604
        (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
 
63605
        (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
 
63606
        (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
 
63607
};
 
63608
duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
 
63609
        (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
 
63610
        (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
 
63611
        (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
 
63612
        (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
 
63613
        (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
 
63614
};
 
63615
 
 
63616
#endif  /* DUK_USE_REGEXP_SUPPORT */
 
63617
 
 
63618
#line 1 "duk_unicode_tables.c"
 
63619
/*
 
63620
 *  Unicode support tables automatically generated during build.
 
63621
 */
 
63622
 
 
63623
/* include removed: duk_internal.h */
 
63624
 
 
63625
/*
 
63626
 *  Unicode tables containing ranges of Unicode characters in a
 
63627
 *  packed format.  These tables are used to match non-ASCII
 
63628
 *  characters of complex productions by resorting to a linear
 
63629
 *  range-by-range comparison.  This is very slow, but is expected
 
63630
 *  to be very rare in practical Ecmascript source code, and thus
 
63631
 *  compactness is most important.
 
63632
 *
 
63633
 *  The tables are matched using uni_range_match() and the format
 
63634
 *  is described in src/extract_chars.py.
 
63635
 */
 
63636
 
 
63637
#ifdef DUK_USE_SOURCE_NONBMP
 
63638
/* IdentifierStart production with ASCII excluded */
 
63639
/* duk_unicode_ids_noa[] */
 
63640
/*
 
63641
 *  Automatically generated by extract_chars.py, do not edit!
 
63642
 */
 
63643
 
 
63644
const duk_uint8_t duk_unicode_ids_noa[797] = {
 
63645
249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
 
63646
240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
 
63647
18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
 
63648
101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
 
63649
52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
 
63650
240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
 
63651
2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
 
63652
114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
 
63653
240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
 
63654
26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
 
63655
205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
 
63656
35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
 
63657
180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
 
63658
146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
 
63659
79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
 
63660
251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
 
63661
92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
 
63662
240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
 
63663
122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
 
63664
74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,15,255,0,8,168,15,60,15,
 
63665
255,0,64,190,15,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,47,
 
63666
9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,34,
 
63667
243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
 
63668
240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
 
63669
240,240,255,240,1,169,96,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,
 
63670
175,24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,
 
63671
241,171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,241,91,47,10,
 
63672
47,3,33,46,61,241,79,107,243,127,37,255,223,13,79,33,242,31,15,240,63,11,
 
63673
242,127,14,63,20,87,36,241,207,142,255,226,86,83,2,241,194,20,3,240,127,
 
63674
156,240,107,240,175,184,15,1,50,34,240,191,30,240,223,117,242,107,240,107,
 
63675
240,63,127,243,159,254,42,239,37,243,223,29,255,238,68,255,226,97,248,63,
 
63676
83,255,234,145,255,227,33,255,240,2,44,95,254,18,191,255,0,52,187,31,255,0,
 
63677
18,242,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,
 
63678
98,255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
 
63679
240,1,114,128,255,240,9,92,144,241,176,255,239,39,12,15,206,15,255,0,46,
 
63680
214,255,225,16,0,
 
63681
};
 
63682
#else
 
63683
/* IdentifierStart production with ASCII and non-BMP excluded */
 
63684
/* duk_unicode_ids_noabmp[] */
 
63685
/*
 
63686
 *  Automatically generated by extract_chars.py, do not edit!
 
63687
 */
 
63688
 
 
63689
const duk_uint8_t duk_unicode_ids_noabmp[614] = {
 
63690
249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
 
63691
240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
 
63692
18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
 
63693
101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
 
63694
52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
 
63695
240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
 
63696
2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
 
63697
114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
 
63698
240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
 
63699
26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
 
63700
205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
 
63701
35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
 
63702
180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
 
63703
146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
 
63704
79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
 
63705
251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
 
63706
92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
 
63707
240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
 
63708
122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
 
63709
74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,15,255,0,8,168,15,60,15,
 
63710
255,0,64,190,15,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,47,
 
63711
9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,34,
 
63712
243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
 
63713
240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
 
63714
240,240,255,240,1,169,96,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,
 
63715
175,24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,
 
63716
241,171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,0,
 
63717
};
 
63718
#endif
 
63719
 
 
63720
#ifdef DUK_USE_SOURCE_NONBMP
 
63721
/* IdentifierStart production with Letter and ASCII excluded */
 
63722
/* duk_unicode_ids_m_let_noa[] */
 
63723
/*
 
63724
 *  Automatically generated by extract_chars.py, do not edit!
 
63725
 */
 
63726
 
 
63727
const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
 
63728
255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
 
63729
249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,48,
 
63730
};
 
63731
#else
 
63732
/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
 
63733
/* duk_unicode_ids_m_let_noabmp[] */
 
63734
/*
 
63735
 *  Automatically generated by extract_chars.py, do not edit!
 
63736
 */
 
63737
 
 
63738
const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
 
63739
255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
 
63740
249,0,
 
63741
};
 
63742
#endif
 
63743
 
 
63744
#ifdef DUK_USE_SOURCE_NONBMP
 
63745
/* IdentifierPart production with IdentifierStart and ASCII excluded */
 
63746
/* duk_unicode_idp_m_ids_noa[] */
 
63747
/*
 
63748
 *  Automatically generated by extract_chars.py, do not edit!
 
63749
 */
 
63750
 
 
63751
const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
 
63752
255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
 
63753
245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
 
63754
36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
 
63755
57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
 
63756
240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
 
63757
242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
 
63758
34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
 
63759
53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
 
63760
211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
 
63761
79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
 
63762
185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
 
63763
4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
 
63764
109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
 
63765
121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
 
63766
240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
 
63767
96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
 
63768
240,162,251,41,241,112,255,225,177,15,254,25,105,255,228,75,34,22,63,26,37,
 
63769
15,254,75,66,242,126,241,25,240,34,241,250,255,240,10,249,228,69,151,54,
 
63770
241,3,248,98,255,228,125,242,47,255,12,23,244,254,0,
 
63771
};
 
63772
#else
 
63773
/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
 
63774
/* duk_unicode_idp_m_ids_noabmp[] */
 
63775
/*
 
63776
 *  Automatically generated by extract_chars.py, do not edit!
 
63777
 */
 
63778
 
 
63779
const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
 
63780
255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
 
63781
245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
 
63782
36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
 
63783
57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
 
63784
240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
 
63785
242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
 
63786
34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
 
63787
53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
 
63788
211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
 
63789
79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
 
63790
185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
 
63791
4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
 
63792
109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
 
63793
121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
 
63794
240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
 
63795
96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
 
63796
240,162,251,41,241,112,0,
 
63797
};
 
63798
#endif
 
63799
 
 
63800
/*
 
63801
 *  Case conversion tables generated using src/extract_caseconv.py.
 
63802
 */
 
63803
 
 
63804
/* duk_unicode_caseconv_uc[] */
 
63805
/* duk_unicode_caseconv_lc[] */
 
63806
 
 
63807
/*
 
63808
 *  Automatically generated by extract_caseconv.py, do not edit!
 
63809
 */
 
63810
 
 
63811
const duk_uint8_t duk_unicode_caseconv_uc[1288] = {
 
63812
132,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
 
63813
128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
 
63814
104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,15,128,15,132,8,31,16,
 
63815
31,24,12,62,64,62,80,32,124,192,124,224,64,250,0,250,64,97,246,1,246,129,3,
 
63816
238,3,247,64,135,220,135,242,2,15,187,15,237,2,31,120,31,248,4,62,244,63,
 
63817
212,8,125,240,127,232,16,253,128,253,192,33,253,1,253,128,67,252,3,253,0,
 
63818
136,92,8,88,8,18,104,18,91,26,44,48,44,0,94,90,0,33,64,155,253,7,252,132,
 
63819
212,0,32,32,32,6,0,76,192,76,129,128,157,0,156,136,1,75,1,74,46,2,244,2,
 
63820
242,12,6,12,6,8,16,13,8,13,0,48,27,64,27,48,64,57,192,57,162,0,119,192,119,
 
63821
132,128,252,128,252,20,2,35,2,34,18,4,142,4,140,20,13,196,13,192,16,30,200,
 
63822
30,192,192,70,16,70,2,32,145,96,145,70,193,48,129,48,67,130,104,130,104,44,
 
63823
30,1,30,0,150,61,66,61,64,192,125,68,125,100,33,99,65,99,56,50,200,18,200,
 
63824
6,69,157,133,157,96,169,144,105,144,11,211,64,211,64,12,167,35,167,34,15,
 
63825
78,103,78,100,126,157,234,157,228,21,59,253,59,240,90,122,26,122,0,163,128,
 
63826
214,128,214,2,1,197,1,196,6,3,140,3,136,12,7,200,7,196,16,20,0,13,48,32,63,
 
63827
128,63,112,69,142,101,142,64,130,1,136,1,135,4,3,114,3,112,8,26,120,202,
 
63828
120,176,65,1,30,1,29,130,2,105,1,150,5,255,96,22,160,115,128,31,224,47,0,
 
63829
38,32,9,32,47,224,10,96,48,0,72,96,50,64,50,32,50,160,62,192,51,32,51,0,51,
 
63830
64,71,160,51,192,68,0,53,0,52,224,55,224,62,224,59,160,49,192,62,96,62,32,
 
63831
74,5,141,224,74,37,141,160,74,69,142,0,74,96,48,32,74,128,48,192,75,32,49,
 
63832
224,75,96,50,0,76,0,50,96,76,96,50,128,76,180,241,160,77,0,50,224,77,101,
 
63833
140,64,78,37,141,192,78,64,51,160,78,160,51,224,79,165,140,128,81,0,53,192,
 
63834
81,32,72,128,81,128,72,160,82,64,54,224,104,160,115,32,110,224,110,192,117,
 
63835
128,112,192,120,64,116,96,121,128,113,128,122,0,114,64,122,32,115,0,122,
 
63836
160,116,192,122,192,116,0,122,224,121,224,126,0,115,64,126,32,116,32,126,
 
63837
64,127,32,126,160,114,160,153,224,152,3,175,52,239,163,175,165,140,99,211,
 
63838
99,204,3,247,192,115,35,252,163,253,132,41,196,38,68,48,132,48,101,140,37,
 
63839
140,5,140,160,71,69,140,192,71,217,128,55,224,5,48,5,48,20,152,10,240,1,56,
 
63840
7,194,0,74,3,12,3,144,192,230,64,194,0,192,64,236,48,58,80,48,128,48,16,88,
 
63841
120,20,212,21,72,122,90,0,72,3,49,30,151,128,21,0,194,7,166,32,5,112,48,
 
63842
161,233,152,1,100,12,40,122,106,0,65,2,190,31,80,128,233,64,196,199,212,
 
63843
176,58,80,49,48,48,1,245,76,14,148,12,76,12,4,125,91,3,165,3,19,3,66,31,
 
63844
128,135,194,0,230,71,224,97,240,144,57,145,248,40,124,40,14,100,126,14,31,
 
63845
11,3,153,31,132,135,195,0,230,71,225,97,240,208,57,145,248,104,124,56,14,
 
63846
100,126,30,31,15,3,153,31,136,135,194,0,230,71,226,97,240,144,57,145,248,
 
63847
168,124,40,14,100,126,46,31,11,3,153,31,140,135,195,0,230,71,227,97,240,
 
63848
208,57,145,248,232,124,56,14,100,126,62,31,15,3,153,31,144,135,202,0,230,
 
63849
71,228,97,242,144,57,145,249,40,124,168,14,100,126,78,31,43,3,153,31,148,
 
63850
135,203,0,230,71,229,97,242,208,57,145,249,104,124,184,14,100,126,94,31,47,
 
63851
3,153,31,152,135,202,0,230,71,230,97,242,144,57,145,249,168,124,168,14,100,
 
63852
126,110,31,43,3,153,31,156,135,203,0,230,71,231,97,242,208,57,145,249,232,
 
63853
124,184,14,100,126,126,31,47,3,153,31,160,135,218,0,230,71,232,97,246,144,
 
63854
57,145,250,40,125,168,14,100,126,142,31,107,3,153,31,164,135,219,0,230,71,
 
63855
233,97,246,208,57,145,250,104,125,184,14,100,126,158,31,111,3,153,31,168,
 
63856
135,218,0,230,71,234,97,246,144,57,145,250,168,125,168,14,100,126,174,31,
 
63857
107,3,153,31,172,135,219,0,230,71,235,97,246,208,57,145,250,232,125,184,14,
 
63858
100,126,190,31,111,3,153,31,178,135,238,128,230,71,236,224,57,16,57,145,
 
63859
251,72,14,24,14,100,126,218,3,145,3,66,31,183,192,228,64,208,128,230,71,
 
63860
239,32,57,16,57,145,252,40,127,40,14,100,127,14,3,151,3,153,31,196,128,226,
 
63861
64,230,71,241,160,57,112,52,33,252,124,14,92,13,8,14,100,127,50,3,151,3,
 
63862
153,31,210,192,230,64,194,0,192,7,244,240,57,144,48,128,48,17,253,104,14,
 
63863
100,13,8,127,95,3,153,3,8,3,66,31,226,192,233,64,194,0,192,7,248,240,58,80,
 
63864
48,128,48,17,254,72,14,132,12,76,127,154,3,165,3,66,31,231,192,233,64,194,
 
63865
0,208,135,252,161,255,160,57,145,255,56,14,164,14,100,127,210,3,143,3,153,
 
63866
31,246,128,234,64,208,135,253,240,58,144,52,32,57,145,255,200,14,164,14,
 
63867
103,236,2,0,70,0,70,251,1,128,17,128,18,126,192,160,4,96,4,207,176,60,1,24,
 
63868
1,24,1,39,236,19,0,70,0,70,0,76,251,5,128,20,192,21,62,193,160,5,48,5,79,
 
63869
177,56,21,16,21,27,236,82,5,68,5,53,251,21,129,81,1,78,254,197,160,84,224,
 
63870
84,111,177,120,21,16,20,244,
 
63871
};
 
63872
const duk_uint8_t duk_unicode_caseconv_lc[616] = {
 
63873
144,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
 
63874
235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
 
63875
0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,15,132,15,128,8,31,24,
 
63876
31,16,12,62,80,62,64,32,124,224,124,192,64,250,64,250,0,97,246,129,246,1,3,
 
63877
241,3,240,2,7,230,7,228,4,15,212,15,208,8,31,184,31,176,4,63,116,62,224,8,
 
63878
127,32,125,200,32,254,192,254,128,33,253,161,247,96,67,253,3,252,0,135,250,
 
63879
135,222,129,15,252,15,188,2,31,250,31,124,4,66,192,66,224,64,146,216,147,
 
63880
64,209,96,1,97,130,242,199,224,35,240,95,228,63,232,38,161,1,0,1,1,48,2,
 
63881
100,2,102,12,4,228,4,232,64,10,80,10,89,112,23,144,23,160,96,48,64,48,96,
 
63882
128,104,0,104,65,128,217,128,218,2,1,203,1,204,18,3,188,3,190,36,7,200,7,
 
63883
204,16,15,192,15,201,64,34,32,34,49,32,72,192,72,225,64,220,0,220,65,1,236,
 
63884
1,236,140,4,96,4,97,34,9,20,9,22,108,19,4,19,8,56,38,128,38,138,193,224,1,
 
63885
224,25,99,212,3,212,44,7,214,71,212,66,22,51,150,52,3,44,128,44,129,100,89,
 
63886
214,89,216,10,153,2,153,4,189,52,5,52,8,202,114,42,114,48,244,230,84,230,
 
63887
103,233,222,105,222,129,83,191,83,191,133,167,160,167,161,10,48,13,48,20,0,
 
63888
32,26,192,26,208,64,56,128,56,192,192,113,64,113,129,1,251,129,252,2,44,
 
63889
114,44,115,4,16,12,56,12,64,32,27,128,27,144,64,211,197,211,198,2,8,6,88,9,
 
63890
164,16,17,216,17,224,47,245,1,120,0,255,1,129,2,83,1,134,2,84,1,142,1,221,
 
63891
1,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,
 
63892
1,153,1,157,2,114,1,159,2,117,1,167,1,168,1,174,2,136,1,183,2,146,1,241,1,
 
63893
243,1,246,1,149,1,247,1,191,2,32,1,158,2,58,44,101,2,61,1,154,2,62,44,102,
 
63894
2,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,
 
63895
3,215,3,244,3,184,3,249,3,242,4,192,4,207,30,158,0,223,31,188,31,179,31,
 
63896
204,31,195,31,236,31,229,31,252,31,243,33,38,3,201,33,42,0,107,33,43,0,229,
 
63897
33,50,33,78,33,131,33,132,44,96,44,97,44,98,2,107,44,99,29,125,44,100,2,
 
63898
125,44,109,2,81,44,110,2,113,44,111,2,80,44,112,2,82,167,125,29,121,167,
 
63899
141,2,101,2,2,97,0,52,129,131,128,
 
63900
};
 
63901
 
 
63902
#line 1 "duk_util_bitdecoder.c"
 
63903
/*
 
63904
 *  Bitstream decoder.
 
63905
 */
 
63906
 
 
63907
/* include removed: duk_internal.h */
 
63908
 
 
63909
/* Decode 'bits' bits from the input stream (bits must be 1...24).
 
63910
 * When reading past bitstream end, zeroes are shifted in.  The result
 
63911
 * is signed to match duk_bd_decode_flagged.
 
63912
 */
 
63913
duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
 
63914
        duk_small_int_t shift;
 
63915
        duk_uint32_t mask;
 
63916
        duk_uint32_t tmp;
 
63917
 
 
63918
        /* Note: cannot read more than 24 bits without possibly shifting top bits out.
 
63919
         * Fixable, but adds complexity.
 
63920
         */
 
63921
        DUK_ASSERT(bits >= 1 && bits <= 24);
 
63922
 
 
63923
        while (ctx->currbits < bits) {
 
63924
#if 0
 
63925
                DUK_DDDPRINT("decode_bits: shift more data (bits=%d, currbits=%d)", bits, ctx->currbits);
 
63926
#endif
 
63927
                ctx->currval <<= 8;
 
63928
                if (ctx->offset < ctx->length) {
 
63929
                        /* If ctx->offset >= ctx->length, we "shift zeroes in"
 
63930
                         * instead of croaking.
 
63931
                         */
 
63932
                        ctx->currval |= ctx->data[ctx->offset++];
 
63933
                }
 
63934
                ctx->currbits += 8;
 
63935
        }
 
63936
#if 0
 
63937
        DUK_DDDPRINT("decode_bits: bits=%d, currbits=%d, currval=0x%08x", bits, ctx->currbits, ctx->currval);
 
63938
#endif
 
63939
 
 
63940
        /* Extract 'top' bits of currval; note that the extracted bits do not need
 
63941
         * to be cleared, we just ignore them on next round.
 
63942
         */
 
63943
        shift = ctx->currbits - bits;
 
63944
        mask = (1 << bits) - 1;
 
63945
        tmp = (ctx->currval >> shift) & mask;
 
63946
        ctx->currbits = shift;  /* remaining */
 
63947
 
 
63948
#if 0
 
63949
        DUK_DDDPRINT("decode_bits: %d bits -> 0x%08x (%d), currbits=%d, currval=0x%08x",
 
63950
                     bits, tmp, tmp, ctx->currbits, ctx->currval);
 
63951
#endif
 
63952
 
 
63953
        return tmp;
 
63954
}
 
63955
 
 
63956
duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
 
63957
        return (duk_small_int_t) duk_bd_decode(ctx, 1);
 
63958
}
 
63959
 
 
63960
/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
 
63961
 * default value.  Return value is signed so that negative marker value can be
 
63962
 * used by caller as a "not present" value.
 
63963
 */
 
63964
duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
 
63965
        if (duk_bd_decode_flag(ctx)) {
 
63966
                return (duk_int32_t) duk_bd_decode(ctx, bits);
 
63967
        } else {
 
63968
                return def_value;
 
63969
        }
 
63970
}
 
63971
 
 
63972
#line 1 "duk_util_bitencoder.c"
 
63973
/*
 
63974
 *  Bitstream encoder.
 
63975
 */
 
63976
 
 
63977
/* include removed: duk_internal.h */
 
63978
 
 
63979
void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
 
63980
        duk_uint8_t tmp;
 
63981
 
 
63982
        DUK_ASSERT(ctx != NULL);
 
63983
        DUK_ASSERT(ctx->currbits < 8);
 
63984
 
 
63985
        /* This limitation would be fixable but adds unnecessary complexity. */
 
63986
        DUK_ASSERT(bits >= 1 && bits <= 24);
 
63987
 
 
63988
        ctx->currval = (ctx->currval << bits) | data;
 
63989
        ctx->currbits += bits;
 
63990
 
 
63991
        while (ctx->currbits >= 8) {
 
63992
                if (ctx->offset < ctx->length) {
 
63993
                        tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
 
63994
                        ctx->data[ctx->offset++] = tmp;
 
63995
                } else {
 
63996
                        /* If buffer has been exhausted, truncate bitstream */
 
63997
                        ctx->truncated = 1;
 
63998
                }
 
63999
 
 
64000
                ctx->currbits -= 8;
 
64001
        }
 
64002
}
 
64003
 
 
64004
void duk_be_finish(duk_bitencoder_ctx *ctx) {
 
64005
        duk_small_int_t npad;
 
64006
 
 
64007
        DUK_ASSERT(ctx != NULL);
 
64008
        DUK_ASSERT(ctx->currbits < 8);
 
64009
 
 
64010
        npad = (duk_small_int_t) (8 - ctx->currbits);
 
64011
        if (npad > 0) {
 
64012
                duk_be_encode(ctx, 0, npad);
 
64013
        }
 
64014
        DUK_ASSERT(ctx->currbits == 0);
 
64015
}
 
64016
 
 
64017
#line 1 "duk_util_hashbytes.c"
 
64018
/*
 
64019
 *  Hash function duk_util_hashbytes().
 
64020
 *
 
64021
 *  Currently, 32-bit MurmurHash2.
 
64022
 *
 
64023
 *  Don't rely on specific hash values; hash function may be endianness
 
64024
 *  dependent, for instance.
 
64025
 */
 
64026
 
 
64027
/* include removed: duk_internal.h */
 
64028
 
 
64029
/* 'magic' constants for Murmurhash2 */
 
64030
#define DUK__MAGIC_M  ((duk_uint32_t) 0x5bd1e995UL)
 
64031
#define DUK__MAGIC_R  24
 
64032
 
 
64033
duk_uint32_t duk_util_hashbytes(duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
 
64034
        duk_uint32_t h = seed ^ len;
 
64035
 
 
64036
        while (len >= 4) {
 
64037
                /* Portability workaround is required for platforms without
 
64038
                 * unaligned access.  The replacement code emulates little
 
64039
                 * endian access even on big endian architectures, which is
 
64040
                 * OK as long as it is consistent for a build.
 
64041
                 */
 
64042
#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
 
64043
                duk_uint32_t k = *((duk_uint32_t *) data);
 
64044
#else
 
64045
                duk_uint32_t k = ((duk_uint32_t) data[0]) |
 
64046
                                 (((duk_uint32_t) data[1]) << 8) |
 
64047
                                 (((duk_uint32_t) data[2]) << 16) |
 
64048
                                 (((duk_uint32_t) data[3]) << 24);
 
64049
#endif
 
64050
 
 
64051
                k *= DUK__MAGIC_M;
 
64052
                k ^= k >> DUK__MAGIC_R;
 
64053
                k *= DUK__MAGIC_M;
 
64054
                h *= DUK__MAGIC_M;
 
64055
                h ^= k;
 
64056
                data += 4;
 
64057
                len -= 4;
 
64058
        }
 
64059
 
 
64060
        switch (len) {
 
64061
                case 3: h ^= data[2] << 16;
 
64062
                case 2: h ^= data[1] << 8;
 
64063
                case 1: h ^= data[0];
 
64064
                        h *= DUK__MAGIC_M;
 
64065
        }
 
64066
 
 
64067
        h ^= h >> 13;
 
64068
        h *= DUK__MAGIC_M;
 
64069
        h ^= h >> 15;
 
64070
 
 
64071
        return h;
 
64072
}
 
64073
 
 
64074
#line 1 "duk_util_hashprime.c"
 
64075
/*
 
64076
 *  Round a number upwards to a prime (not usually the nearest one).
 
64077
 *
 
64078
 *  Uses a table of successive 32-bit primes whose ratio is roughly
 
64079
 *  constant.  This keeps the relative upwards 'rounding error' bounded
 
64080
 *  and the data size small.  A simple 'predict-correct' compression is
 
64081
 *  used to compress primes to one byte per prime.  See genhashsizes.py
 
64082
 *  for details.
 
64083
 *
 
64084
 *  The minimum prime returned here must be coordinated with the possible
 
64085
 *  probe sequence steps in duk_hobject and duk_heap stringtable.
 
64086
 */
 
64087
 
 
64088
/* include removed: duk_internal.h */
 
64089
 
 
64090
/* hash size ratio goal, must match genhashsizes.py */
 
64091
#define DUK__HASH_SIZE_RATIO   1177  /* floor(1.15 * (1 << 10)) */
 
64092
 
 
64093
/* prediction corrections for prime list (see genhashsizes.py) */
 
64094
static const duk_int8_t duk__hash_size_corrections[] = {
 
64095
        17,  /* minimum prime */
 
64096
        4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
 
64097
        5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
 
64098
        8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
 
64099
        18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
 
64100
        22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
 
64101
        43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
 
64102
        10, 23, 16, 9, 2,
 
64103
        -1
 
64104
};
 
64105
 
 
64106
/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
 
64107
 * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
 
64108
 */
 
64109
duk_uint8_t duk_util_probe_steps[32] = {
 
64110
        2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
 
64111
        109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
 
64112
};
 
64113
 
 
64114
duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
 
64115
        const duk_int8_t *p = duk__hash_size_corrections;
 
64116
        duk_uint32_t curr;
 
64117
 
 
64118
        curr = (duk_uint32_t) *p++;
 
64119
        for (;;) {
 
64120
                duk_small_int_t t = (duk_small_int_t) *p++;
 
64121
                if (t < 0) {
 
64122
                        /* may happen if size is very close to 2^32-1 */
 
64123
                        break;
 
64124
                }
 
64125
 
 
64126
                /* prediction: portable variant using doubles if 64-bit values not available */
 
64127
#ifdef DUK_USE_64BIT_OPS
 
64128
                curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
 
64129
#else
 
64130
                /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
 
64131
                curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
 
64132
#endif
 
64133
 
 
64134
                /* correction */
 
64135
                curr += t;
 
64136
 
 
64137
                DUK_DDDPRINT("size=%d, curr=%d", size, curr);
 
64138
 
 
64139
                if (curr >= size) {
 
64140
                        return curr;
 
64141
                }
 
64142
        }
 
64143
        return 0;
 
64144
}
 
64145
 
 
64146
#line 1 "duk_util_misc.c"
 
64147
/*
 
64148
 *  Misc util stuff
 
64149
 */
 
64150
 
 
64151
/* include removed: duk_internal.h */
 
64152
 
 
64153
/*
 
64154
 *  Lowercase digits for radix values 2 to 36.  Also doubles as lowercase
 
64155
 *  hex nybble table.
 
64156
 */
 
64157
 
 
64158
duk_uint8_t duk_lc_digits[36] = { '0', '1', '2', '3', '4', '5', '6', '7',
 
64159
                                  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
 
64160
                                  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
 
64161
                                  'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
 
64162
                                  'w', 'x', 'y', 'z' };
 
64163
 
 
64164
duk_uint8_t duk_uc_nybbles[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
 
64165
                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
64166
#line 1 "duk_util_tinyrandom.c"
 
64167
/*
 
64168
 *  A tiny random number generator.
 
64169
 *
 
64170
 *  Currently used for Math.random().
 
64171
 *
 
64172
 *  http://www.woodmann.com/forum/archive/index.php/t-3100.html
 
64173
 */
 
64174
 
 
64175
/* include removed: duk_internal.h */
 
64176
 
 
64177
#define DUK__UPDATE_RND(rnd) do { \
 
64178
                (rnd) += ((rnd) * (rnd)) | 0x05; \
 
64179
                (rnd) = ((rnd) & 0xffffffffU);       /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
 
64180
        } while (0)
 
64181
 
 
64182
#define DUK__RND_BIT(rnd)  ((rnd) >> 31)  /* only use the highest bit */
 
64183
 
 
64184
duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
 
64185
        duk_small_int_t i;
 
64186
        duk_uint32_t res = 0;
 
64187
        duk_uint32_t rnd;
 
64188
 
 
64189
        rnd = thr->heap->rnd_state;
 
64190
 
 
64191
        for (i = 0; i < n; i++) {
 
64192
                DUK__UPDATE_RND(rnd);
 
64193
                res <<= 1;
 
64194
                res += DUK__RND_BIT(rnd);
 
64195
        }
 
64196
 
 
64197
        thr->heap->rnd_state = rnd;
 
64198
 
 
64199
        return res;
 
64200
}
 
64201
 
 
64202
duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
 
64203
        duk_double_t t;
 
64204
        duk_small_int_t n;
 
64205
        duk_uint32_t rnd;
 
64206
 
 
64207
        /*
 
64208
         *  XXX: could make this a lot faster if we create the double memory
 
64209
         *  representation directly.  Feasible easily (must be uniform random).
 
64210
         */
 
64211
 
 
64212
        rnd = thr->heap->rnd_state;
 
64213
 
 
64214
        n = 53;  /* enough to cover the whole mantissa */
 
64215
        t = 0.0;
 
64216
 
 
64217
        do {
 
64218
                DUK__UPDATE_RND(rnd);
 
64219
                t += DUK__RND_BIT(rnd);
 
64220
                t /= 2.0;
 
64221
        } while (--n);
 
64222
 
 
64223
        thr->heap->rnd_state = rnd;
 
64224
 
 
64225
        DUK_ASSERT(t >= (duk_double_t) 0.0);
 
64226
        DUK_ASSERT(t < (duk_double_t) 1.0);
 
64227
 
 
64228
        return t;
 
64229
}
 
64230